Commit fd52a421 authored by Tristan Cavelier's avatar Tristan Cavelier

Merge remote-tracking branch 's3/master' into s3storage

Conflicts:
	Gruntfile.js
	Makefile
	README.md
	complex_queries.js
	examples/example.html
	examples/jio_dashboard.html
	jio.js
	package.json
	src/jio.storage/cryptstorage.js
	src/jio.storage/davstorage.js
	src/jio.storage/erp5storage.js
	src/jio.storage/gidstorage.js
	src/jio.storage/indexstorage.js
	src/jio.storage/localstorage.js
	src/jio.storage/replicaterevisionstorage.js
	src/jio.storage/replicatestorage.js
	src/jio.storage/revisionstorage.js
	src/jio.storage/s3storage.js
	src/jio.storage/xwikistorage.js
	src/jio/core/globals.js
	src/jio/core/restCommandRejecter.js
	src/jio/core/restCommandResolver.js
	src/jio/core/util.js
	src/jio/features/jobChecker.js
	src/jio/features/jobExecuter.js
	src/jio/features/jobQueue.js
	src/jio/features/jobRetry.js
	src/jio/intro.js
	test/jio.storage/davstorage.tests.js
	test/jio.storage/gidstorage.tests.js
	test/jio.storage/indexstorage.tests.js
	test/jio.storage/localstorage.tests.js
	test/jio.storage/replicaterevisionstorage.tests.js
	test/jio.storage/revisionstorage.tests.js
	test/jio.storage/s3storage.tests.js
	test/jio.storage/splitstorage.tests.js
	test/jio.storage/xwikistorage.tests.js
	test/jio/tests.js
	test/queries/tests.js
	test/run-qunit.js
	test/tests.html
	test/tests.require.js
parents 5fd24a93 a8b327e0
/*
* Copyright 2013, Nexedi SA
* Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html
*/
/*jslint indent:2, maxlen: 80, nomen: true */
/*global jIO, define, Blob */
/**
* Provides a split storage for JIO. This storage splits data
* and store them in the sub storages defined on the description.
*
* {
* "type": "split",
* "storage_list": [<storage description>, ...]
* }
*/
// define([dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO);
}(['jio'], function (jIO) {
"use strict";
/**
* Generate a new uuid
*
* @method generateUuid
* @private
* @return {String} The new uuid
*/
function generateUuid() {
function S4() {
/* 65536 */
var i, string = Math.floor(
Math.random() * 0x10000
).toString(16);
for (i = string.length; i < 4; i += 1) {
string = '0' + string;
}
return string;
}
return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() +
S4() + S4();
}
/**
* Select a storage to put the document part
*
* @method selectStorage
* @private
* @return {Object} The selected storage
*/
function selectStorage(arg, iteration) {
var step = iteration % arg.length;
return arg[step];
}
/**
* Class to merge allDocs responses from several sub storages.
*
* @class AllDocsResponseMerger
* @constructor
*/
function AllDocsResponseMerger() {
/**
* A list of allDocs response.
*
* @attribute response_list
* @type {Array} Contains allDocs responses
* @default []
*/
this.response_list = [];
}
AllDocsResponseMerger.prototype.constructor = AllDocsResponseMerger;
/**
* Add an allDocs response to the response list.
*
* @method addResponse
* @param {Object} response The allDocs response.
* @return {AllDocsResponseMerger} This
*/
AllDocsResponseMerger.prototype.addResponse = function (response) {
this.response_list.push(response);
return this;
};
/**
* Add several allDocs responses to the response list.
*
* @method addResponseList
* @param {Array} response_list An array of allDocs responses.
* @return {AllDocsResponseMerger} This
*/
AllDocsResponseMerger.prototype.addResponseList = function (response_list) {
var i;
for (i = 0; i < response_list.length; i += 1) {
this.response_list.push(response_list[i]);
}
return this;
};
/**
* Merge the response_list to one allDocs response.
*
* The merger will find rows with the same id in order to merge them, thanks
* to the onRowToMerge method. If no row correspond to an id, rows with the
* same id will be ignored.
*
* @method merge
* @param {Object} [option={}] The merge options
* @param {Boolean} [option.include_docs=false] Tell the merger to also
* merge metadata if true.
* @return {Object} The merged allDocs response.
*/
AllDocsResponseMerger.prototype.merge = function (option) {
var result = [], row, to_merge = [], tmp, i;
if (this.response_list.length === 0) {
return [];
}
/*jslint ass: true */
while ((row = this.response_list[0].data.rows.shift()) !== undefined) {
to_merge[0] = row;
for (i = 1; i < this.response_list.length; i += 1) {
to_merge[i] = AllDocsResponseMerger.listPopFromRowId(
this.response_list[i].data.rows,
row.id
);
if (to_merge[i] === undefined) {
break;
}
}
tmp = this.onRowToMerge(to_merge, option || {});
if (tmp !== undefined) {
result[result.length] = tmp;
}
}
this.response_list = [];
return {"total_rows": result.length, "rows": result};
};
/**
* This method is called when the merger want to merge several rows with the
* same id.
*
* @method onRowToMerge
* @param {Array} row_list An array of rows.
* @param {Object} [option={}] The merge option.
* @param {Boolean} [option.include_docs=false] Also merge the metadata if
* true
* @return {Object} The merged row
*/
AllDocsResponseMerger.prototype.onRowToMerge = function (row_list, option) {
var i, k, new_row = {"value": {}}, data = "";
option = option || {};
for (i = 0; i < row_list.length; i += 1) {
new_row.id = row_list[i].id;
if (row_list[i].key) {
new_row.key = row_list[i].key;
}
if (option.include_docs) {
new_row.doc = new_row.doc || {};
for (k in row_list[i].doc) {
if (row_list[i].doc.hasOwnProperty(k)) {
if (k[0] === "_") {
new_row.doc[k] = row_list[i].doc[k];
}
}
}
data += row_list[i].doc.data;
}
}
if (option.include_docs) {
try {
data = JSON.parse(data);
} catch (e) { return undefined; }
for (k in data) {
if (data.hasOwnProperty(k)) {
new_row.doc[k] = data[k];
}
}
}
return new_row;
};
/**
* Search for a specific row and pop it. During the search operation, all
* parsed rows are stored on a dictionnary in order to be found instantly
* later.
*
* @method listPopFromRowId
* @param {Array} rows The row list
* @param {String} doc_id The document/row id
* @return {Object/undefined} The poped row
*/
AllDocsResponseMerger.listPopFromRowId = function (rows, doc_id) {
var row;
if (!rows.dict) {
rows.dict = {};
}
if (rows.dict[doc_id]) {
row = rows.dict[doc_id];
delete rows.dict[doc_id];
return row;
}
/*jslint ass: true*/
while ((row = rows.shift()) !== undefined) {
if (row.id === doc_id) {
return row;
}
rows.dict[row.id] = row;
}
};
/**
* The split storage class used by JIO.
*
* A split storage instance is able to i/o on several sub storages with
* split documents.
*
* @class SplitStorage
*/
function SplitStorage(spec) {
var that = this, priv = {};
/**
* The list of sub storages we want to use to store part of documents.
*
* @attribute storage_list
* @private
* @type {Array} Array of storage descriptions
*/
priv.storage_list = spec.storage_list;
//////////////////////////////////////////////////////////////////////
// Tools
/**
* Send a command to all sub storages. All the response are returned
* in a list. The index of the response correspond to the storage_list
* index. If an error occurs during operation, the callback is called with
* `callback(err, undefined)`. The response is given with
* `callback(undefined, response_list)`.
*
* `doc` is the document informations but can also be a list of dedicated
* document informations. In this case, each document is associated to one
* sub storage.
*
* @method send
* @private
* @param {String} method The command method
* @param {Object,Array} doc The document information to send to each sub
* storages or a list of dedicated document
* @param {Object} option The command option
* @param {Function} callback Called at the end
*/
priv.send = function (command, method, doc, option, callback) {
var i, answer_list = [], failed = false, currentServer;
function onEnd() {
i += 1;
if (i === priv.storage_list.length) {
callback(undefined, answer_list);
}
}
function onSuccess(i) {
return function (response) {
if (!failed) {
answer_list[i] = response;
}
onEnd();
};
}
function onError(i) {
return function (err) {
if (!failed) {
failed = true;
err.index = i;
callback(err, undefined);
}
};
}
if (!Array.isArray(doc)) {
for (i = 0; i < doc.length; i += 1) {
currentServer = selectStorage(priv.storage_list, i, doc.length);
if (method === 'allDocs') {
command.storage(currentServer)[method](option).
then(onSuccess(i), onError(i));
} else {
command.storage(currentServer)[method](doc, option).
then(onSuccess(i), onError(i));
}
}
} else {
for (i = 0; i < doc.length; i += 1) {
currentServer = selectStorage(priv.storage_list, i, doc.length);
// we assume that alldocs is not called if the there is several docs
command.storage(priv.storage_list[i])[method](doc[i], option).
then(onSuccess(i), onError(i));
}
}
//default splitstorage method
/*
if (!Array.isArray(doc)) {
for (i = 0; i < priv.storage_list.length; i += 1) {
if (method === 'allDocs') {
command.storage(priv.storage_list[i])[method](option).
then(onSuccess(i), onError(i));
} else {
command.storage(priv.storage_list[i])[method](doc, option).
then(onSuccess(i), onError(i));
}
}
} else {
for (i = 0; i < priv.storage_list.length; i += 1) {
// we assume that alldocs is not called if the there is several docs
command.storage(priv.storage_list[i])[method](doc[i], option).
then(onSuccess(i), onError(i));
}
}
*/
//re-init
i = 0;
};
/**
* Split document metadata then store them to the sub storages.
*
* @method postOrPut
* @private
* @param {Object} doc A serialized document object
* @param {Object} option Command option properties
* @param {String} method The command method ('post' or 'put')
*/
priv.postOrPut = function (command, doc, option, method) {
var i, data, doc_list = [], doc_underscores = {};
if (!doc._id) {
doc._id = generateUuid(); // XXX should let gidstorage guess uid
// in the future, complete id with gidstorage
}
for (i in doc) {
if (doc.hasOwnProperty(i)) {
if (i[0] === "_") {
doc_underscores[i] = doc[i];
delete doc[i];
}
}
}
data = JSON.stringify(doc);
//for (i = 0; i < priv.storage_list.length; i += 1) {
//doc_list[i] = JSON.parse(JSON.stringify(doc_underscores));
//doc_list[i].data = data.slice(
//(data.length / priv.storage_list.length) * i,
//(data.length / priv.storage_list.length) * (i + 1)
//);
//console.info('doc_list[i].data');
//console.log(doc_list[i].data);
//}
for (i = 0; i < 100; i += 1) {
doc_list[i] = JSON.parse(JSON.stringify(doc_underscores));
doc_list[i]._id = doc_list[i]._id + '_' + i;
doc_list[i].data = data.slice(
(data.length / 100) * i,
(data.length / 100) * (i + 1)
);
}
priv.send(command, method, doc_list, option, function (err) {
if (err) {
err.message = "Unable to " + method + " document";
delete err.index;
return command.error(err);
}
command.success({"id": doc_underscores._id});
});
};
//////////////////////////////////////////////////////////////////////
// JIO commands
/**
* Split document metadata then store them to the sub storages.
*
* @method post
* @param {Object} command The JIO command
*/
that.post = function (command, metadata, option) {
priv.postOrPut(command, metadata, option, 'post');
};
/**
* Split document metadata then store them to the sub storages.
*
* @method put
* @param {Object} command The JIO command
*/
that.put = function (command, metadata, option) {
priv.postOrPut(command, metadata, option, 'put');
};
/**
* Puts an attachment to the sub storages.
*
* @method putAttachment
* @param {Object} command The JIO command
*/
that.putAttachment = function (command, param, option) {
var i, attachment_list = [], data = param._blob;
for (i = 0; i < priv.storage_list.length; i += 1) {
attachment_list[i] = jIO.util.deepClone(param);
attachment_list[i]._blob = data.slice(
data.size * i / priv.storage_list.length,
data.size * (i + 1) / priv.storage_list.length,
data.type
);
}
priv.send(
command,
'putAttachment',
attachment_list,
option,
function (err) {
if (err) {
err.message = "Unable to put attachment";
delete err.index;
return command.error(err);
}
command.success();
}
);
};
/**
* Gets splited document metadata then returns real document.
*
* @method get
* @param {Object} command The JIO command
*/
that.get = function (command, param, option) {
var doc = param;
priv.send(command, 'get', doc, option, function (err, response) {
var i, k;
if (err) {
err.message = "Unable to get document";
delete err.index;
return command.error(err);
}
doc = '';
for (i = 0; i < response.length; i += 1) {
response[i] = response[i].data;
doc += response[i].data;
}
doc = JSON.parse(doc);
for (i = 0; i < response.length; i += 1) {
for (k in response[i]) {
if (response[i].hasOwnProperty(k)) {
if (k[0] === "_") {
doc[k] = response[i][k];
}
}
}
}
delete doc._attachments;
for (i = 0; i < response.length; i += 1) {
if (response[i]._attachments) {
for (k in response[i]._attachments) {
if (response[i]._attachments.hasOwnProperty(k)) {
doc._attachments = doc._attachments || {};
doc._attachments[k] = doc._attachments[k] || {
"length": 0,
"content_type": ""
};
doc._attachments[k].length += response[i]._attachments[k].
length;
// if (response[i]._attachments[k].digest) {
// if (doc._attachments[k].digest) {
// doc._attachments[k].digest += " " + response[i].
// _attachments[k].digest;
// } else {
// doc._attachments[k].digest = response[i].
// _attachments[k].digest;
// }
// }
doc._attachments[k].content_type = response[i]._attachments[k].
content_type;
}
}
}
}
command.success({"data": doc});
});
};
/**
* Gets splited document attachment then returns real attachment data.
*
* @method getAttachment
* @param {Object} command The JIO command
*/
that.getAttachment = function (command, param, option) {
priv.send(command, 'getAttachment', param, option, function (
err,
response
) {
if (err) {
err.message = "Unable to get attachment";
delete err.index;
return command.error(err);
}
command.success({"data": new Blob(response.map(function (answer) {
return answer.data;
}), {"type": response[0].data.type})});
});
};
/**
* Removes a document from the sub storages.
*
* @method remove
* @param {Object} command The JIO command
*/
that.remove = function (command, param, option) {
priv.send(
command,
'remove',
param,
option,
function (err) {
if (err) {
err.message = "Unable to remove document";
delete err.index;
return command.error(err);
}
command.success();
}
);
};
/**
* Removes an attachment from the sub storages.
*
* @method removeAttachment
* @param {Object} command The JIO command
*/
that.removeAttachment = function (command, param, option) {
priv.send(
command,
'removeAttachment',
param,
option,
function (err) {
if (err) {
err.message = "Unable to remove attachment";
delete err.index;
return command.error(err);
}
command.success();
}
);
};
/**
* Retreive a list of all document in the sub storages.
*
* If include_docs option is false, then it returns the document list from
* the first sub storage. Else, it will merge results and return.
*
* @method allDocs
* @param {Object} command The JIO command
*/
that.allDocs = function (command, param, option) {
option = {"include_docs": option.include_docs};
priv.send(
command,
'allDocs',
param,
option,
function (err, response_list) {
var all_docs_merger;
if (err) {
err.message = "Unable to retrieve document list";
delete err.index;
return command.error(err);
}
all_docs_merger = new AllDocsResponseMerger();
all_docs_merger.addResponseList(response_list);
return command.success({"data": all_docs_merger.merge(option)});
}
);
};
} // end of splitStorage
jIO.addStorage('split', SplitStorage);
}));
......@@ -16,17 +16,22 @@
"use strict";
var b64_hmac_sha1 = sha1.b64_hmac_sha1;
jIO.addStorageType("s3", function (spec, my) {
var that, priv = {};
spec = spec || {};
that = my.basicStorage(spec, my);
jIO.addStorage("s3", function (spec) {
var that, priv = {}, lastDigest, isDelete;
that = this;
//nomenclature param
// param._id,
// ._attachment,
// ._blob
// attributes
priv.username = spec.username || '';
priv.AWSIdentifier = spec.AWSIdentifier || '';
priv.password = spec.password || '';
priv.server = spec.server || ''; /*|| jiobucket ||*/
priv.acl = spec.acl || '';
priv.server = spec.server || '';
/*||> "private,
public-read,
......@@ -35,8 +40,8 @@
bucket-owner-read,
bucket-owner-full-control" <||*/
priv.acl = spec.acl || '';
priv.actionStatus = spec.actionStatus || '';
priv.contenTType = spec.contenTType || '';
/**
......@@ -255,9 +260,6 @@
return StringToSign;
};
that.encodePolicy = function () {
//generates the policy
//enables the choice for the http response code
......@@ -268,10 +270,7 @@
{"bucket": priv.server },
["starts-with", "$key", ""],
{"acl": priv.acl },
{"success_action_redirect": ""},
{"success_action_status": undefined }, // http_code
["starts-with", "$Content-Type", ""],
["content-length-range", 0, 524288000]
["starts-with", "$Content-Type", ""]
]
};
......@@ -303,52 +302,41 @@
this.status === 200) {
switch (http) {
case "POST":
that.success({
ok: true,
id: docId
});
command.success(this.status, {id: docId});
break;
case 'PUT':
if (jio === true) {
that.success({
ok: true,
id: command.getDocId()
});
command.success(this.status);
} else {
callback(this.responseText);
}
break;
case 'GET':
if (jio === true) {
if (typeof this.responseText !== 'string') {
response = JSON.parse(this.responseText);
response._attachments = response._attachments || {};
delete response._attachments;
that.success(JSON.stringify(response));
if (isAttachment === true) {
//méthode that.getAttachment
response = this.response;
command.success(
this.status,
{'data': response, 'digest': lastDigest}
);
} else {
if (isAttachment === true) {
that.success(this.responseText);
} else {
that.success(JSON.parse(this.responseText));
}
// this is not an attachment
// that.get method
response = JSON.parse(this.responseText);
command.success(this.status, {'data': response});
}
} else {
callback(this.responseText);
}
break;
case 'DELETE':
if (jio === true) {
if (isAttachment === false) {
that.success({
ok: true,
id: command.getDocId()
});
command.success(this.status);
} else {
that.success({
ok: true,
id: command.getDocId(),
attachment: command.getAttachmentId()
});
command.success(this.status);
}
} else {
callback(this.responseText);
......@@ -364,7 +352,7 @@
//reason "reason"
//message "did not work"
err.error = "not_allowed";
that.error(err);
command.error(err);
}
if (this.status === 404) {
if (http === 'GET') {
......@@ -374,32 +362,48 @@
//error
//reason "reason"
//message "did not work"
err.statustext = "not_foud";
err.reason = "file does not exist";
err.error = "not_found";
that.error(err);
} else {
callback('404');
return command.error(
404,
"Not Found",
"File does not exist"
);
}
//not jio
if (isDelete === true) {
isDelete = false;
return command.error(
404,
"Not Found",
"File does not exist"
);
}
callback('404');
} else {
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err.error = "not_found";
that.error(err);
return command.error(
404,
"Not Found",
"File does not exist"
);
}
//fin 404
}
if (this.status === 409) {
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err.error = "already_exists";
that.error(err);
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
return command.error(
409,
"Already Exists",
"File does exist"
);
}
}
}
......@@ -430,30 +434,6 @@
return doc;
};
priv.createError = function (status, message, reason) {
var error = {
"status": status,
"message": message,
"reason": reason
};
switch (status) {
case 404:
error.statusText = "Not found";
break;
case 405:
error.statusText = "Method Not Allowed";
break;
case 409:
error.statusText = "Conflicts";
break;
case 24:
error.statusText = "Corrupted Document";
break;
}
error.error = error.statusText.toLowerCase().split(" ").join("_");
return error;
};
that.encodeAuthorization = function (key) {
//GET oriented method
var requestUTC, httpVerb, StringToSign, Signature;
......@@ -472,14 +452,14 @@
};
that.XHRwrapper = function (command,
docId,
attachId,
http,
mime,
data,
jio,
is_attachment,
callback) {
docId,
attachId,
http,
mime,
data,
jio,
is_attachment,
callback) {
var docFile, requestUTC, StringToSign, url, Signature, xhr;
docFile = priv.secureName(priv.idsToFileName(docId,
......@@ -509,7 +489,13 @@
+ ":"
+ Signature);
xhr.setRequestHeader("Content-Type", mime);
xhr.responseType = 'text';
if (http === 'GET' && jio === true && is_attachment === true) {
xhr.responseType = 'blob';
} else {
//défaut
xhr.responseType = 'text';
}
xhr_onreadystatechange(docId,
command,
......@@ -533,21 +519,20 @@
* @param {object} command The JIO command
**/
that.post = function (command) {
that.post = function (command, metadata) {
//as S3 encoding key are directly inserted within the FormData(),
//use of XHRwrapper function ain't pertinent
var doc, doc_id, mime;
doc = command.cloneDoc();
doc_id = command.getDocId();
doc = metadata;
doc_id = doc._id;
function postDocument() {
var http_response, fd, Signature, xhr;
var fd, Signature, xhr;
doc_id = priv.secureName(priv.idsToFileName(doc_id));
//Meant to deep-serialize in order to avoid
//conflicts due to the multipart enctype
doc = JSON.stringify(doc);
http_response = '';
fd = new FormData();
//virtually builds the form fields
//filename
......@@ -559,15 +544,15 @@
priv.contenTType = "text/plain";
fd.append('Content-Type', priv.contenTType);
//allows specification of a success url redirection
fd.append('success_action_redirect', '');
//fd.append('success_action_redirect', '');
//allows to specify the http code response if the request is successful
fd.append('success_action_status', http_response);
//fd.append('success_action_status', http_response);
//login AWS
fd.append('AWSAccessKeyId', priv.AWSIdentifier);
//exchange policy with the amazon s3 service
//can be common to all uploads or specific
//that.encodePolicy(fd);
that.encodePolicy(fd);
//priv.b64_policy = that.encodePolicy(fd);
fd.append('policy', priv.b64_policy);
//signature through the base64.hmac.sha1(secret key, policy) method
Signature = b64_hmac_sha1(priv.password, priv.b64_policy);
......@@ -594,14 +579,13 @@
} else {
//si ce n'est pas une 404,
//alors on renvoit une erreur 405
return that.error(priv.createError(
return command.error(
409,
"Cannot create document",
"Document already exists"
));
"Document already exists",
"Cannot create document"
);
}
}
);
});
};
/**
......@@ -610,22 +594,50 @@
* @param {object} command The JIO command
**/
that.get = function (command) {
var docId, attachId, isJIO, mime;
docId = command.getDocId();
attachId = command.getAttachmentId() || '';
that.get = function (command, metadata) {
var docId, isJIO, mime;
docId = metadata._id;
isJIO = true;
mime = 'text/plain; charset=UTF-8';
that.XHRwrapper(command, docId, attachId, 'GET', mime, '', isJIO, false);
that.XHRwrapper(command, docId, '', 'GET', mime, '', isJIO, false);
};
that.getAttachment = function (command) {
that.getAttachment = function (command, param) {
var docId, attachId, isJIO, mime;
docId = command.getDocId();
attachId = command.getAttachmentId();
isJIO = true;
mime = 'text/plain; charset=UTF-8';
that.XHRwrapper(command, docId, attachId, 'GET', mime, '', isJIO, true);
function getTheAttachment() {
docId = param._id;
attachId = param._attachment;
isJIO = true;
mime = 'text/plain; charset=UTF-8';
that.XHRwrapper(command, docId, attachId, 'GET', mime, '', isJIO, true);
}
function getDoc() {
docId = param._id;
isJIO = false;
mime = 'text/plain; charset=UTF-8';
that.XHRwrapper(command, docId, '', 'GET', mime, '', isJIO, false,
function (response) {
var responseObj = JSON.parse(response)._attachments;
if (responseObj !== undefined) {
if (responseObj[param._attachment] !== undefined) {
lastDigest = JSON.parse(response).
_attachments[param._attachment].digest;
}
}
getTheAttachment();
});
}
getDoc();
//docId = param._id;
//attachId = param._attachment;
//isJIO = true;
//mime = 'text/plain; charset=UTF-8';
//that.XHRwrapper(command, docId, attachId, 'GET', mime,
// '', isJIO, true);
};
/**
......@@ -634,10 +646,10 @@
* @param {object} command The JIO command
**/
that.put = function (command) {
that.put = function (command, metadata) {
var doc, docId, mime;
doc = command.cloneDoc();
docId = command.getDocId();
doc = metadata;
docId = doc._id;
mime = 'text/plain; charset=UTF-8';
//pas d'attachment dans un put simple
function putDocument() {
......@@ -657,94 +669,95 @@
that.XHRwrapper(command, docId, '', 'GET', mime, '', false, false,
function (response) {
//if (response === '404') {}
if (response._attachments !== undefined) {
doc._attachments = response._attachments;
var responseObj = JSON.parse(response);
if (responseObj._attachments !== undefined) {
doc._attachments = responseObj._attachments;
}
putDocument();
}
);
// XXX control non existing document to throw a 201 http code
});
};
that.putAttachment = function (command) {
var mon_document,
that.putAttachment = function (command, param) {
var my_document,
docId,
attachId,
mime,
attachment_data,
attachment_md5,
attachment_digest,
attachment_mimetype,
attachment_length;
mon_document = null;
docId = command.getDocId();
attachId = command.getAttachmentId() || '';
mime = 'text/plain; charset=UTF-8';
//récupération des variables de l'attachement
my_document = null;
docId = param._id;
attachId = param._attachment;
mime = param._blob.type;
attachment_data = param._blob;
jIO.util.readBlobAsBinaryString(param._blob).then(function (e) {
var binary_string = e.target.result;
attachment_digest = jIO.util.makeBinaryStringDigest(binary_string);
function putAttachment() {
that.XHRwrapper(
command,
docId,
attachId,
'PUT',
mime,
attachment_data,
false,
true,
function () {
command.success({
// response
"digest": attachment_digest
});
}
);
}
//attachment_id = command.getAttachmentId();
attachment_data = command.getAttachmentData();
attachment_md5 = command.md5SumAttachmentData();
attachment_mimetype = command.getAttachmentMimeType();
attachment_length = command.getAttachmentLength();
function putDocument() {
var attachment_obj, data, doc;
attachment_mimetype = param._blob.type;
attachment_length = param._blob.size;
function putAttachment() {
that.XHRwrapper(command,
docId,
attachId,
'PUT',
mime,
attachment_data,
false,
true,
function () {
that.success({
// response
"ok": true,
"id": docId,
"attachment": attachId
//"rev": current_revision
});
}
);
}
attachment_obj = {
//"revpos": 3, // optional
"digest": attachment_digest,
"content_type": attachment_mimetype,
"length": attachment_length
};
function putDocument() {
var attachment_obj, data, doc;
attachment_obj = {
//"revpos": 3, // optional
"digest": attachment_md5,
"content_type": attachment_mimetype,
"length": attachment_length
};
data = JSON.parse(mon_document);
data = JSON.parse(my_document);
doc = priv.updateMeta(data, docId, attachId, "add", attachment_obj);
doc = priv.updateMeta(data, docId, attachId, "add", attachment_obj);
that.XHRwrapper(command, docId, '', 'PUT', mime, doc, false, false,
function () {
putAttachment();
}
);
}
that.XHRwrapper(command, docId, '', 'PUT', mime, doc, false, false,
function () {
putAttachment();
});
}
function getDocument() {
//XHRwrapper(command,'PUT','text/plain; charset=UTF-8',true);
that.XHRwrapper(command, docId, '', 'GET', mime, '', false, false,
function (reponse) {
if (reponse === '404') {
return that.error(priv.createError(
404,
"Cannot find document",
"Document does not exist"
));
}
mon_document = reponse;
putDocument();
}
);
}
getDocument();
function getDocument() {
that.XHRwrapper(command, docId, '', 'GET', mime, '', false, false,
function (response) {
if (response === '404') {
return command.error(
404,
"Document does not exist",
"Cannot find document"
);
}
my_document = response;
putDocument();
});
}
getDocument();
});
};
/**
......@@ -753,15 +766,16 @@
* @param {object} command The JIO command
*/
that.remove = function (command) {
that.remove = function (command, param) {
var docId, mime;
docId = command.getDocId();
docId = param._id;
mime = 'text/plain; charset=UTF-8';
isDelete = true;
function deleteDocument() {
isDelete = false;
that.XHRwrapper(command, docId, '', 'DELETE', mime, '', true, false,
function () {
that.success({
command.success({
// response
"ok": true,
"id": docId
......@@ -798,23 +812,23 @@
);
};
that.removeAttachment = function (command) {
var mon_document,
that.removeAttachment = function (command, param) {
var my_document,
docId,
attachId,
mime;
mon_document = null;
docId = command.getDocId();
attachId = command.getAttachmentId() || '';
my_document = null;
docId = param._id;
attachId = param._attachment;
mime = 'text/plain; charset=UTF-8';
//récupération des variables de l'attachement
// attachment_id = command.getAttachmentId();
// attachment_data = command.getAttachmentData();
// attachment_md5 = command.md5SumAttachmentData();
// attachment_mimetype = command.getAttachmentMimeType();
// attachment_length = command.getAttachmentLength();
//attachment_id = command.getAttachmentId();
//attachment_data = command.getAttachmentData();
//attachment_md5 = command.md5SumAttachmentData();
//attachment_mimetype = command.getAttachmentMimeType();
//attachment_length = command.getAttachmentLength();
function removeAttachment() {
that.XHRwrapper(command, docId, attachId, 'DELETE', mime, '', true,
......@@ -825,7 +839,8 @@
function putDocument() {
var data, doc;
data = JSON.parse(mon_document);
//data = JSON.parse(my_document);
data = my_document;
doc = priv.updateMeta(data, docId, attachId, "remove", '');
that.XHRwrapper(command, docId, '', 'PUT', mime, doc,
false, false, function () {
......@@ -835,11 +850,32 @@
function getDocument() {
that.XHRwrapper(command, docId, '', 'GET', mime, '', false, false,
function (reponse) {
mon_document = reponse;
putDocument();
}
);
function (response) {
if (response === '404') {
return command.error(
404,
"missing document",
"This Document does not exist"
);
}
my_document = JSON.parse(response);
if (my_document._attachments === undefined) {
return command.error(
404,
"missing attachment",
"This Document has no attachments"
);
}
if (my_document._attachments[attachId] !== undefined) {
putDocument();
} else {
return command.error(
404,
"missing attachment",
"This Attachment does not exist"
);
}
});
}
getDocument();
};
......@@ -850,9 +886,10 @@
* @param {object} command The JIO command
**/
that.allDocs = function (command) {
var mon_document, mime;
mon_document = null;
that.allDocs = function (command, param, options) {
/*jslint unparam: true */
var my_document, mime;
my_document = null;
mime = 'text/plain; charset=UTF-8';
function makeJSON() {
......@@ -870,7 +907,7 @@
callURL,
requestUTC;
keys = $(mon_document).find('Key');
keys = $(my_document).find('Key');
resultTable = [];
counter = 0;
......@@ -892,7 +929,6 @@
allDocResponse = {
// document content will be added to response
"total_rows": resultTable.length,
"offset": 0,
"rows": []
};
......@@ -905,7 +941,7 @@
return function (doc, statustext, response) {
allDoc.rows[i].doc = response.responseText;
if (count === 0) {
that.success(allDoc);
command.success(allDoc);
} else {
count -= 1;
}
......@@ -914,13 +950,8 @@
errCallback = function (err) {
if (err.status === 404) {
//status
//statustext "Not Found"
//error
//reason "reason"
//message "did not work"
err.error = "not_found";
that.error(err);
command.error(err);
} else {
return that.retry(err);
}
......@@ -928,20 +959,16 @@
i = resultTable.length - 1;
if (command.getOption("include_docs") === true) {
if (options.include_docs) {
for (i; i >= 0; i -= 1) {
keyId = resultTable[i];
Signature = that.encodeAuthorization(keyId);
callURL = 'http://' + priv.server + '.s3.amazonaws.com/' + keyId;
requestUTC = new Date().toUTCString();
allDocResponse.rows[i] = {
"id": priv.fileNameToIds(keyId).join(),
"key": keyId,
"value": {}
};
$.ajax({
contentType : '',
crossdomain : true,
......@@ -961,7 +988,7 @@
//'x-amz-security-token' : ,
},
success : dealCallback(i, countB, allDocResponse),
error : errCallback(that.error)
error : errCallback(command.error)
});
countB += 1;
}
......@@ -970,11 +997,11 @@
keyId = resultTable[i];
allDocResponse.rows[i] = {
"id": priv.fileNameToIds(keyId).join(),
"key": keyId,
"value": {}
};
}
that.success(allDocResponse);
allDocResponse = {"data": allDocResponse};
command.success(allDocResponse);
}
}
......@@ -982,16 +1009,13 @@
//XHRwrapper(command,'PUT','text/plain; charset=UTF-8',true);
that.XHRwrapper(command, '', '', 'GET', mime, '', false, false,
function (reponse) {
mon_document = reponse;
my_document = reponse;
makeJSON();
}
);
}
getXML();
//fin alldocs
};
return that;
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, test_util, RSVP, test, ok, deepEqual, module, stop,
start, hex_sha256 */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, test_util, RSVP);
}([
'jio',
'test_util',
'rsvp',
'localstorage',
'splitstorage'
], function (jIO, util, RSVP) {
"use strict";
var tool = {
"readBlobAsBinaryString": jIO.util.readBlobAsBinaryString
};
function reverse(promise) {
return new RSVP.Promise(function (resolve, reject, notify) {
promise.then(reject, resolve, notify);
}, function () {
promise.cancel();
});
}
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called
* with no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
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) {
if (Array.isArray(thens[i])) {
promises[i + 1] = promises[i].
then(thens[i][0], thens[i][1], thens[i][2]);
} else {
promises[i + 1] = promises[i].then(thens[i]);
}
}
promises[i].then(resolve, reject, notify);
}, function () {
var i;
for (i = 0; i < promises.length; i += 1) {
promises[i].cancel();
}
});
}
function unexpectedError(error) {
if (error instanceof Error) {
deepEqual([
error.name + ": " + error.message,
error
], "UNEXPECTED ERROR", "Unexpected error");
} else {
deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
}
}
module("SplitStorage + LocalStorage");
test("Post", function () {
var shared = {}, jio, jio_local_list = [];
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "post1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "post2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
jio_local_list[0] = jIO.createJIO(shared.local_storage_description1, {
"workspace": shared.workspace
});
jio_local_list[1] = jIO.createJIO(shared.local_storage_description2, {
"workspace": shared.workspace
});
jio_local_list.run = function (method, argument) {
var i, promises = [];
for (i = 0; i < this.length; i += 1) {
promises[i] = this[i][method].apply(this[i], argument);
}
return RSVP.all(promises);
};
jio_local_list.get = function () {
return this.run("get", arguments);
};
stop();
// post without id
jio.post({
"_underscored_meta": "uvalue",
"meta": "data"
}).then(function (answer) {
shared.uuid = answer.id;
answer.id = "<uuid>";
ok(util.isUuid(shared.uuid), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + shared.uuid);
deepEqual(answer, {
"id": "<uuid>",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post document without id");
// check uploaded documents
return jio_local_list.get({"_id": shared.uuid});
}).then(function (answers) {
var i;
for (i = 0; i < answers.length; i += 1) {
deepEqual(answers[i].data, {
"_id": shared.uuid,
"_underscored_meta": "uvalue",
"data": i === 0 ? "{\"meta\"" : ":\"data\"}"
}, "Check uploaded document in sub storage " + (i + 1));
}
// post with id
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
});
}).then(function (answer) {
deepEqual(answer, {
"id": "one",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post document with id");
// check uploaded documents
return jio_local_list.get({"_id": "one"});
}).then(function (answers) {
deepEqual(answers[0].data, {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "{\"meta\":\"data\","
}, "Check uploaded document in sub storage 1");
deepEqual(answers[1].data, {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "\"hello\":\"world\"}"
}, "Check uploaded document in sub storage 2");
// post with id
return reverse(jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
}));
}).then(function (answer) {
deepEqual(answer, {
"error": "conflict",
"id": "one",
"message": "Unable to post document",
"method": "post",
"reason": "document exists",
"result": "error",
"status": 409,
"statusText": "Conflict"
}, "Post document with same id -> 409 Conflict");
}).fail(unexpectedError).always(start);
});
test("PutAttachment", function () {
var shared = {}, jio, jio_local_list = [];
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "putAttachment1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "putAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
jio_local_list[0] = jIO.createJIO(shared.local_storage_description1, {
"workspace": shared.workspace
});
jio_local_list[1] = jIO.createJIO(shared.local_storage_description2, {
"workspace": shared.workspace
});
jio_local_list.run = function (method, argument) {
var i, promises = [];
for (i = 0; i < this.length; i += 1) {
promises[i] = this[i][method].apply(this[i], argument);
}
return RSVP.all(promises);
};
jio_local_list.get = function () {
return this.run("get", arguments);
};
jio_local_list.getAttachmentAsBinaryString = function () {
return this.run("getAttachment", arguments).then(function (answers) {
var i, promises = [];
for (i = 0; i < answers.length; i += 1) {
promises[i] = tool.readBlobAsBinaryString(answers[i].data);
}
return RSVP.all(promises);
});
};
stop();
return reverse(jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_content_type": "text/plain"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to put attachment",
"method": "putAttachment",
"reason": "missing",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Put attachment on a inexistent document -> 404 Not Found");
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"id": "one",
"method": "putAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put attachment on a document");
// check uploaded documents
return jio_local_list.get({"_id": "one"});
}).then(function (answers) {
deepEqual(answers[0].data, {
"_attachments": {
"my_attachment": {
"content_type": "text/plain",
"digest": "sha256-ebf2d770a6a2dfa135f6c81431f22fc3cbcde9ae" +
"e52759ca9e520d4d964c1322", // sha256("My ")
"length": 3
}
},
"_id": "one",
"_underscored_meta": "uvalue",
"data": "{\"meta\""
}, "Check uploaded document in sub storage 1");
deepEqual(answers[1].data, {
"_attachments": {
"my_attachment": {
"content_type": "text/plain",
"digest": "sha256-cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b" +
"3cdf79496dc442d52b8dd528", // sha256("Data")
"length": 4
}
},
"_id": "one",
"_underscored_meta": "uvalue",
"data": ":\"data\"}"
}, "Check uploaded document in sub storage 2");
return jio_local_list.getAttachmentAsBinaryString({
"_id": "one",
"_attachment": "my_attachment"
});
}).then(function (events) {
deepEqual(events[0].target.result, "My ",
"Check uploaded document in sub storage 1");
deepEqual(events[1].target.result, "Data",
"Check uploaded document in sub storage 1");
}).fail(unexpectedError).always(start);
});
test("Get", function () {
var shared = {}, jio;
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "get1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "get2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.get({"_id": "one"})).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "one",
"message": "Unable to get document",
"method": "get",
"reason": "missing",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get missing document");
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.get({"_id": "one"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Get posted document");
return jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_content_type": "text/plain"
});
}).then(function () {
return jio.get({"_id": "one"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"_attachments": {
"my_attachment": {
"length": 7,
"content_type": "text/plain"
}
}
}, "Get document with attachment informations");
}).fail(unexpectedError).always(start);
});
test("GetAttachment", function () {
var shared = {}, jio;
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "getAttachment1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "getAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.getAttachment({
"_id": "one",
"_attachment": "my_attachment"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "missing document",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get attachment from missing document -> 404 Not Found");
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return reverse(jio.getAttachment({
"_id": "one",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "missing attachment",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get missing attachment from document");
return jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function () {
return jio.getAttachment({"_id": "one", "_attachment": "my_attachment"});
}).then(function (answer) {
return tool.readBlobAsBinaryString(answer.data);
}).then(function (event) {
deepEqual(event.target.result, "My Data", "Get attachment");
}).fail(unexpectedError).always(start);
});
test("RemoveAttachment", function () {
var shared = {}, jio;
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "removeAttachment1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "removeAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.removeAttachment({
"_id": "one",
"_attachment": "my_attachment"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to remove attachment",
"method": "removeAttachment",
"reason": "missing document",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove attachment from inexistent document -> 404 Not Found");
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return reverse(jio.removeAttachment({
"_id": "one",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to remove attachment",
"method": "removeAttachment",
"reason": "missing attachment",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove inexistent attachment -> 404 Not Found");
return jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function () {
return jio.removeAttachment({
"_id": "one",
"_attachment": "my_attachment"
});
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"id": "one",
"method": "removeAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove attachment");
return jio.get({"_id": "one"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Check document");
return reverse(jio.getAttachment({
"_id": "one",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "missing attachment",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check attachment -> 404 Not Found");
}).fail(unexpectedError).always(start);
});
test("Remove", function () {
var shared = {}, jio;
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "remove1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "remove2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.remove({"_id": "one"})).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "one",
"message": "Unable to remove document",
"method": "remove",
"reason": "missing",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove missing document -> 404 Not Found");
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function () {
return jio.remove({"_id": "one"});
}).then(function (answer) {
deepEqual(answer, {
"id": "one",
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove document");
return reverse(jio.getAttachment({
"_id": "one",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "one",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "missing document",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check attachment -> 404 Not Found");
return reverse(jio.get({"_id": "one"}));
}).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "one",
"message": "Unable to get document",
"method": "get",
"reason": "missing",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check document -> 404 Not Found");
}).fail(unexpectedError).always(start);
});
test("Put", function () {
var shared = {}, jio;
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "put1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "put2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
stop();
jio.put({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}).then(function (answer) {
deepEqual(answer, {
"id": "one",
"method": "put",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put new document");
return jio.get({"_id": "one"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Check document");
return jio.put({
"_id": "one",
"_underscored_meta": "uvalue",
"meow": "dog"
});
}).then(function (answer) {
deepEqual(answer, {
"id": "one",
"method": "put",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put same document again");
return jio.get({"_id": "one"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "one",
"_underscored_meta": "uvalue",
"meow": "dog"
}, "Get document for check");
}).fail(unexpectedError).always(start);
});
test("AllDocs", function () {
var shared = {}, jio;
shared.workspace = {};
shared.local_storage_description1 = {
"type": "local",
"username": "splitstorage",
"application_name": "alldocs1",
"mode": "memory"
};
shared.local_storage_description2 = {
"type": "local",
"username": "splitstorage",
"application_name": "alldocs2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.local_storage_description1,
shared.local_storage_description2
]
}, {"workspace": shared.workspace});
stop();
function prepareDatabase() {
var i, do_list = [];
function post(i) {
return function () {
return jio.post({
"_id": "doc" + i,
"_underscored_meta": "uvalue" + i,
"meta": "data" + i
});
};
}
function putAttachment(i) {
return function () {
return jio.putAttachment({
"_id": "doc" + i,
"_attachment": "my_attachment" + i,
"_data": "My Data" + i,
"_content_type": "text/plain"
});
};
}
for (i = 0; i < 5; i += 1) {
do_list.push(post(i));
}
for (i = 0; i < 2; i += 1) {
do_list.push(putAttachment(i));
}
return sequence(do_list);
}
prepareDatabase().then(function () {
return jio.get({"_id": "doc1"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "doc1",
"_underscored_meta": "uvalue1",
"meta": "data1",
"_attachments": {
"my_attachment1": {
"length": 8,
"content_type": "text/plain"
}
}
}, "Check document");
return jio.allDocs();
}).then(function (answer) {
answer.data.rows.sort(function (a, b) {
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
});
deepEqual(answer.data, {
"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");
}).fail(unexpectedError).always(start);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, test_util, RSVP, test, ok, deepEqual, module, stop,
start, hex_sha256 */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, test_util, RSVP);
}([
'jio',
'test_util',
'rsvp',
's3storage',
'multisplitstorage'
], function (jIO, util, RSVP) {
"use strict";
var tool = {
"readBlobAsBinaryString": jIO.util.readBlobAsBinaryString
};
function reverse(promise) {
return new RSVP.Promise(function (resolve, reject, notify) {
promise.then(reject, resolve, notify);
}, function () {
promise.cancel();
});
}
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called
* with no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
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) {
if (Array.isArray(thens[i])) {
promises[i + 1] = promises[i].
then(thens[i][0], thens[i][1], thens[i][2]);
} else {
promises[i + 1] = promises[i].then(thens[i]);
}
}
promises[i].then(resolve, reject, notify);
}, function () {
var i;
for (i = 0; i < promises.length; i += 1) {
promises[i].cancel();
}
});
}
function unexpectedError(error) {
if (error instanceof Error) {
deepEqual([
error.name + ": " + error.message,
error
], "UNEXPECTED ERROR", "Unexpected error");
} else {
deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
}
}
module("SplitStorage + S3 Storage");
test("Post", function () {
var shared = {}, jio, jio_s3_list = [];
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
jio_s3_list[0] = jIO.createJIO(shared.s3_storage_description1, {
"workspace": shared.workspace
});
jio_s3_list[1] = jIO.createJIO(shared.s3_storage_description2, {
"workspace": shared.workspace
});
jio_s3_list.run = function (method, argument) {
var i, promises = [];
for (i = 0; i < this.length; i += 1) {
promises[i] = this[i][method].apply(this[i], argument);
}
return RSVP.all(promises);
};
jio_s3_list.get = function () {
return this.run("get", arguments);
};
stop();
// post without id
jio.post({
"_underscored_meta": "uvalue",
"meta": "data"
})
.then(function (answer) {
shared.uuid = answer.id;
answer.id = "<uuid>";
ok(util.isUuid(shared.uuid), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + shared.uuid);
deepEqual(answer, {
"id": "<uuid>",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post document without id");
// check uploaded documents
return jio_s3_list.get({"_id": shared.uuid});
})
.then(function (answers) {
var i;
for (i = 0; i < answers.length; i += 1) {
deepEqual(answers[i].data, {
"_id": shared.uuid,
"_underscored_meta": "uvalue",
"data": i === 0 ? "{\"meta\"" : ":\"data\"}"
}, "Check uploaded document in sub storage " + (i + 1));
}
// post with id
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
});
})
.then(function (answer) {
deepEqual(answer, {
"id": "one",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post document with id");
// check uploaded documents
return jio_s3_list.get({"_id": "one"});
})
.then(function (answers) {
deepEqual(answers[0].data, {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "{\"meta\":\"data\","
}, "Check uploaded document in sub storage 1");
deepEqual(answers[1].data, {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "\"hello\":\"world\"}"
}, "Check uploaded document in sub storage 2");
// post with id
return reverse(jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
}));
})
.then(function (answer) {
deepEqual(answer, {
"error": "conflict",
"id": "one",
"message": "Unable to post document",
"method": "post",
"reason": "Document already exists",
"result": "error",
"status": 409,
"statusText": "Conflict"
}, "Post document with same id -> 409 Conflict");
})
.fail(unexpectedError).always(start);
});
/*
test("PutAttachment", function () {
var shared = {}, jio, jio_s3_list = [];
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "putAttachment1",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "putAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
jio_s3_list[0] = jIO.createJIO(shared.s3_storage_description1, {
"workspace": shared.workspace
});
jio_s3_list[1] = jIO.createJIO(shared.s3_storage_description2, {
"workspace": shared.workspace
});
jio_s3_list.run = function (method, argument) {
var i, promises = [];
for (i = 0; i < this.length; i += 1) {
promises[i] = this[i][method].apply(this[i], argument);
}
return RSVP.all(promises);
};
jio_s3_list.get = function () {
return this.run("get", arguments);
};
jio_s3_list.getAttachmentAsBinaryString = function () {
return this.run("getAttachment", arguments).then(function (answers) {
var i, promises = [];
for (i = 0; i < answers.length; i += 1) {
promises[i] = tool.readBlobAsBinaryString(answers[i].data);
}
return RSVP.all(promises);
});
};
stop();
return reverse(jio.putAttachment({
"_id": "two",
"_attachment": "my_attachment",
"_data": "My Data",
"_content_type": "text/plain"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "two",
"message": "Unable to put attachment",
"method": "putAttachment",
"reason": "Document does not exist",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Put attachment on a inexistent document -> 404 Not Found");
return jio.post({
"_id": "two",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.putAttachment({
"_id": "two",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"id": "two",
"method": "putAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put attachment on a document");
// check uploaded documents
return jio_s3_list.get({"_id": "two"});
}).then(function (answers) {
deepEqual(answers[0].data, {
"_attachments": {
"my_attachment": {
"content_type": "text/plain",
"digest": "sha256-ebf2d770a6a2dfa135f6c81431f22fc3cbcde9ae" +
"e52759ca9e520d4d964c1322", // sha256("My ")
"length": 3
}
},
"_id": "two",
"_underscored_meta": "uvalue",
"data": "{\"meta\""
}, "Check uploaded document in sub storage 1");
deepEqual(answers[1].data, {
"_attachments": {
"my_attachment": {
"content_type": "text/plain",
"digest": "sha256-cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b" +
"3cdf79496dc442d52b8dd528", // sha256("Data")
"length": 4
}
},
"_id": "two",
"_underscored_meta": "uvalue",
"data": ":\"data\"}"
}, "Check uploaded document in sub storage 2");
return jio_s3_list.getAttachmentAsBinaryString({
"_id": "two",
"_attachment": "my_attachment"
});
}).then(function (events) {
deepEqual(events[0].target.result, "My ",
"Check uploaded document in sub storage 1");
deepEqual(events[1].target.result, "Data",
"Check uploaded document in sub storage 1");
}).fail(unexpectedError).always(start);
});
*/
/*
test("Get", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "get1",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "get2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.get({"_id": "three"})).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "three",
"message": "Unable to get document",
"method": "get",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get missing document");
return jio.post({
"_id": "three",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.get({"_id": "three"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "three",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Get posted document");
return jio.putAttachment({
"_id": "three",
"_attachment": "my_attachment",
"_data": "My Data",
"_content_type": "text/plain"
});
}).then(function () {
return jio.get({"_id": "three"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "three",
"_underscored_meta": "uvalue",
"meta": "data",
"_attachments": {
"my_attachment": {
"length": 7,
"content_type": "text/plain"
}
}
}, "Get document with attachment informations");
}).fail(unexpectedError).always(start);
});
*/
/*
test("GetAttachment", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "getAttachment",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "getAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.getAttachment({
"_id": "four",
"_attachment": "my_attachment"
}))
.then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "four",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get attachment from missing document -> 404 Not Found");
return jio.post({
"_id": "four",
"_underscored_meta": "uvalue",
"meta": "data"
});
})
.then(function () {
return reverse(jio.getAttachment({
"_id": "four",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "four",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get missing attachment from document");
return jio.putAttachment({
"_id": "four",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
})
.then(function () {
return jio.getAttachment({
"_id": "four",
"_attachment": "my_attachment"
});
}).then(function (answer) {
return tool.readBlobAsBinaryString(answer.data);
}).then(function (event) {
deepEqual(event.target.result, "My Data", "Get attachment");
})
.fail(unexpectedError).always(start);
});
*/
/*
test("RemoveAttachment", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.removeAttachment({
"_id": "five",
"_attachment": "my_attachment"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "five",
"message": "Unable to remove attachment",
"method": "removeAttachment",
"reason": "missing document",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove attachment from inexistent document -> 404 Not Found");
return jio.post({
"_id": "five",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return reverse(jio.removeAttachment({
"_id": "five",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "five",
"message": "Unable to remove attachment",
"method": "removeAttachment",
"reason": "missing attachment",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove inexistent attachment -> 404 Not Found");
return jio.putAttachment({
"_id": "five",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
})
.then(function () {
return jio.removeAttachment({
"_id": "five",
"_attachment": "my_attachment"
});
})
.then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"id": "five",
"method": "removeAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove attachment");
return jio.get({"_id": "five"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "five",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Check document");
return reverse(jio.getAttachment({
"_id": "five",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "five",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check attachment -> 404 Not Found");
})
.fail(unexpectedError).always(start);
});
*/
/*
test("Remove", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.remove({"_id": "six"})).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "six",
"message": "Unable to remove document",
"method": "remove",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove missing document -> 404 Not Found");
return jio.post({
"_id": "six",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.putAttachment({
"_id": "six",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function () {
return jio.remove({"_id": "six"});
}).then(function (answer) {
deepEqual(answer, {
"id": "six",
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove document");
return reverse(jio.getAttachment({
"_id": "six",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "six",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check attachment -> 404 Not Found");
return reverse(jio.get({"_id": "six"}));
}).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "six",
"message": "Unable to get document",
"method": "get",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check document -> 404 Not Found");
}).fail(unexpectedError).always(start);
});
*/
/*
test("Put", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
jio.put({
"_id": "seven",
"_underscored_meta": "uvalue",
"meta": "data"
}).then(function (answer) {
deepEqual(answer, {
"id": "seven",
"method": "put",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put new document");
return jio.get({"_id": "seven"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "seven",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Check document");
return jio.put({
"_id": "seven",
"_underscored_meta": "uvalue",
"meow": "dog"
});
}).then(function (answer) {
deepEqual(answer, {
"id": "seven",
"method": "put",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put same document again");
return jio.get({"_id": "seven"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "seven",
"_underscored_meta": "uvalue",
"meow": "dog"
}, "Get document for check");
}).fail(unexpectedError).always(start);
});
*/
/*
test("AllDocs", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucket_alldocs",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucket_alldocs_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
function prepareDatabase() {
var i, do_list = [];
function post(i) {
return function () {
return jio.post({
"_id": "doc" + i,
"_underscored_meta": "uvalue" + i,
"meta": "data" + i
});
};
}
function putAttachment(i) {
return function () {
return jio.putAttachment({
"_id": "doc" + i,
"_attachment": "my_attachment" + i,
"_data": "My Data" + i,
"_content_type": "text/plain"
});
};
}
for (i = 0; i < 5; i += 1) {
do_list.push(post(i));
}
for (i = 0; i < 2; i += 1) {
do_list.push(putAttachment(i));
}
return sequence(do_list);
}
prepareDatabase().then(function () {
return jio.get({"_id": "doc1"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "doc1",
"_underscored_meta": "uvalue1",
"meta": "data1",
"_attachments": {
"my_attachment1": {
"length": 8,
"content_type": "text/plain"
}
}
}, "Check document");
return jio.allDocs();
}).then(function (answer) {
answer.data.rows.sort(function (a, b) {
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
});
deepEqual(answer.data, {
"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");
}).fail(unexpectedError).always(start);
});
*/
}));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JIO S3 Storage Qunit Live Tests</title>
<link rel="stylesheet" href="../../lib/qunit/qunit.css" />
<script src="../../lib/qunit/qunit.js"></script>
<script src="../../lib/rsvp/rsvp-custom.js"></script>
<script src="../../lib/jquery/jquery.min.js"></script>
<script src="../../src/sha256.amd.js"></script>
<script src="../../jio.js"></script>
<script src="../../complex_queries.js"></script>
<script src="../../src/sha1.amd.js"></script>
<script src="../../src/jio.storage/s3storage.js"></script>
<script src="../../src/jio.storage/multisplitstorage.js"></script>
<script src="../jio/util.js"></script>
</head>
<body>
<script>
var s3storage_spec = {};
console.log(location.href);
location.href.split('?')[1].split('&').forEach(function (item) {
s3storage_spec[item.split('=')[0]] = decodeURI(item.split('=').slice(1).join('=')).
replace(/%3A/ig, ':').replace(/%2F/ig, '/');
});
</script>
<h3>JIO initialization</h3>
<form method="get" action="">
<input type="hidden" name="type" value="s3"/>
<input type="text" name="url" placeholder="URL" value="https://jiobucket.s3.amazonaws.com"/>
<input type="text" name="server" placeholder="Bucket" value="jiobucket"/>
<input type="text" name="AWSIdentifier" placeholder="AWSIdentifier" value="AKIAJLNYGVLTV66RHPEQ"/>
<input type="password" name="password" placeholder="Password" value="/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"/>
<input type="submit" value="Run Tests"/>
</form>
<br />
<div id="qunit"></div>
<!--<script src="s3storage.tests.js"></script>-->
<script src="multi.split.s3storage.tests.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JIO S3 Storage Qunit Live Tests</title>
<link rel="stylesheet" href="../../lib/qunit/qunit.css" />
<script src="../../lib/qunit/qunit.js"></script>
<script src="../../lib/rsvp/rsvp-custom.js"></script>
<script src="../../lib/jquery/jquery.min.js"></script>
<script src="../../src/sha256.amd.js"></script>
<script src="../../jio.js"></script>
<script src="../../complex_queries.js"></script>
<script src="../../src/sha1.amd.js"></script>
<script src="../../src/jio.storage/s3storage.js"></script>
<script src="../../src/jio.storage/splitstorage.js"></script>
<script src="../jio/util.js"></script>
</head>
<body>
<script>
var s3storage_spec = {};
console.log(location.href);
location.href.split('?')[1].split('&').forEach(function (item) {
s3storage_spec[item.split('=')[0]] = decodeURI(item.split('=').slice(1).join('=')).
replace(/%3A/ig, ':').replace(/%2F/ig, '/');
});
</script>
<h3>JIO initialization</h3>
<form method="get" action="">
<input type="hidden" name="type" value="s3"/>
<input type="text" name="url" placeholder="URL" value="https://jiobucket.s3.amazonaws.com"/>
<input type="text" name="server" placeholder="Bucket" value="jiobucket"/>
<input type="text" name="AWSIdentifier" placeholder="AWSIdentifier" value="AKIAJLNYGVLTV66RHPEQ"/>
<input type="password" name="password" placeholder="Password" value="/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"/>
<input type="submit" value="Run Tests"/>
</form>
<br />
<div id="qunit"></div>
<!--<script src="s3storage.tests.js"></script>-->
<script src="split.s3storage.tests.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>JIO S3 Storage Qunit Live Tests</title>
<link rel="stylesheet" href="../../lib/qunit/qunit.css" />
<script src="../../lib/qunit/qunit.js"></script>
<script src="../../lib/rsvp/rsvp-custom.js"></script>
<script src="../../lib/jquery/jquery.min.js"></script>
<script src="../../src/sha256.amd.js"></script>
<script src="../../jio.js"></script>
<script src="../../complex_queries.js"></script>
<script src="../../src/sha1.amd.js"></script>
<script src="../../src/jio.storage/s3storage.js"></script>
<script src="../jio/util.js"></script>
</head>
<body>
<script>
var s3storage_spec = {};
console.log(location.href);
location.href.split('?')[1].split('&').forEach(function (item) {
s3storage_spec[item.split('=')[0]] = decodeURI(item.split('=').slice(1).join('=')).
replace(/%3A/ig, ':').replace(/%2F/ig, '/');
});
</script>
<h3>JIO initialization</h3>
<form method="get" action="">
<input type="hidden" name="type" value="s3"/>
<input type="text" name="url" placeholder="URL" value="https://jiobucket.s3.amazonaws.com"/>
<input type="text" name="server" placeholder="Bucket" value="jiobucket"/>
<input type="text" name="AWSIdentifier" placeholder="AWSIdentifier" value="AKIAJLNYGVLTV66RHPEQ"/>
<input type="password" name="password" placeholder="Password" value="/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"/>
<input type="submit" value="Run Tests"/>
</form>
<br />
<div id="qunit"></div>
<script src="s3storage.tests.js"></script>
</body>
</html>
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, window, test, ok, deepEqual, sinon, expect,
module */
/*global module, test, stop, start, expect, ok, deepEqual, location, sinon,
davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa, s3storage_spec */
// 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) {
(function () {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
var spec, use_fake_server = true;
if (typeof s3storage_spec === 'object') {
use_fake_server = false;
spec = s3storage_spec;
}
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);
module("S3 Storage");
});
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"
function success(promise) {
return new RSVP.Promise(function (resolve, reject, notify) {
/*jslint unparam: true*/
promise.then(resolve, resolve, notify);
}, function () {
promise.cancel();
});
}
//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);
});
test("Scenario", function () {
/*
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"
var server, responses = [], shared = {}, jio = jIO.createJIO(spec, {
"workspace": {},
"max_retry": 2
});
//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",
[
stop();
if (use_fake_server) {
/*jslint regexp: true */
server = sinon.fakeServer.create();
server.autoRespond = true;
server.autoRespondAfter = 5;
server.respondWith(/.*/, function (xhr) {
var response = responses.shift();
if (response) {
return xhr.respond.apply(xhr, response);
}
ok(false, "No response associated to the latest request!");
});
} else {
responses.push = function () {
return;
};
server = {restore: function () {
return;
}};
}
function postNewDocument() {
responses.push([404, {}, '']); // GET
responses.push([201, {}, '']); // PUT
return jio.post({"title": "Unique ID"});
}
function postNewDocumentTest(answer) {
var uuid = answer.id;
answer.id = "<uuid>";
deepEqual(answer, {
"id": "<uuid>",
"method": "post",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Post a new document");
ok(/^no_document_id_[0-9]+$/.test(uuid), "New document id should look like " +
"no_document_id_479658600408584 : " + uuid);
shared.created_document_id = uuid;
}
function getCreatedDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": shared.created_document_id,
"title": "Unique ID"
})]); // GET
return jio.get({"_id": shared.created_document_id});
}
function getCreatedDocumentTest(answer) {
deepEqual(answer, {
"data": {
"_id": shared.created_document_id,
"title": "Unique ID"
},
"id": shared.created_document_id,
"method": "get",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Get new document");
}
function postSpecificDocument() {
responses.push([404, {}, '']); // GET
responses.push([201, {}, '']); // PUT
return jio.post({"_id": "b", "title": "Bee"});
}
function postSpecificDocumentTest(answer) {
deepEqual(answer, {
"id": "b",
"method": "post",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Post specific document");
}
function listDocuments() {
//quelle utilité à pousser le xml ?
responses.push([
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",
[
{"Content-Type": "text/xml"},''
]); // PROPFIND
return jio.allDocs();
}
function list2DocumentsTest(answer) {
if (answer && answer.data && Array.isArray(answer.data.rows)) {
answer.data.rows.sort(function (a) {
return a.id === "b" ? 1 : 0;
});
}
deepEqual(answer, {
"data": {
"total_rows": 2,
"rows": [{
"id": shared.created_document_id,
"value": {}
}, {
"id": "b",
"value": {}
}]
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List 2 documents");
}
function removeCreatedDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": shared.created_document_id,
"title": "Unique ID"
})]); // GET
responses.push([204, {}, '']); // DELETE
return jio.remove({"_id": shared.created_document_id});
}
function removeCreatedDocumentTest(answer) {
deepEqual(answer, {
"id": shared.created_document_id,
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove first document.");
}
function removeSpecificDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "b",
"title": "Bee"
})]); // GET
responses.push([204, {}, '']); // DELETE
return jio.remove({"_id": "b"});
}
function removeSpecificDocumentTest(answer) {
deepEqual(answer, {
"id": "b",
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove second document.");
}
function listEmptyStorage() {
responses.push([
200,
{"Content-Type": "text/html"},
JSON.stringify({
{"Content-Type": "text/xml"},
''
]); // PROPFIND
return jio.allDocs();
}
function listEmptyStorageTest(answer) {
deepEqual(answer, {
"data": {
"total_rows": 0,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List empty storage");
}
function putNewDocument() {
responses.push([404, {}, '']); // GET
responses.push([200, {}, '']); // PUT
return jio.put({"_id": "a", "title": "Hey"});
}
function putNewDocumentTest(answer) {
deepEqual(answer, {
"id": "a",
"method": "put",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Put new document");
}
function getCreatedDocument2() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hey"
})]); // GET
return jio.get({"_id": "a"});
}
function getCreatedDocument2Test(answer) {
deepEqual(answer, {
"data": {
"_id": "a",
"title": "Hey"
},
"id": "a",
"method": "get",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Get new document");
}
function postSameDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hey"
})]); // GET
return success(jio.post({"_id": "a", "title": "Hoo"}));
}
function postSameDocumentTest(answer) {
deepEqual(answer, {
"error": "conflict",
"id": "a",
"message": "Cannot create document",
"method": "post",
"reason": "Document already exists",
"result": "error",
"status": 409,
"statusText": "Conflict"
}, "Unable to post the same document (conflict)");
}
function createAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hey"
})]); // GET
responses.push([201, {}, '']); // PUT (attachment)
responses.push([204, {}, '']); // PUT (metadata)
return jio.putAttachment({
"_id": "a",
"_attachment": "aa",
"_data": "aaa",
"_content_type": "text/plain"
});
}
function createAttachmentTest(answer) {
deepEqual(answer, {
"attachment": "aa",
"digest":"sha256-9834876dcfb05cb167a5c24953eba58c4"+
"ac89b1adf57f28f2f9d09af107ee8f0",
"id": "a",
"method": "putAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Create new attachment");
}
function updateAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hey",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
}
}
})]); // GET
responses.push([204, {}, '']); // PUT (attachment)
responses.push([204, {}, '']); // PUT (metadata)
return jio.putAttachment({
"_id": "a",
"_attachment": "aa",
"_data": "aab",
"_content_type": "text/plain"
});
}
function updateAttachmentTest(answer) {
deepEqual(answer, {
"attachment": "aa",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"id": "a",
"method": "putAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Update last attachment");
}
function createAnotherAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hey",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
}
}
})]); // GET
responses.push([201, {}, '']); // PUT (attachment)
responses.push([204, {}, '']); // PUT (metadata)
return jio.putAttachment({
"_id": "a",
"_attachment": "ab",
"_data": "aba",
"_content_type": "text/plain"
});
}
function createAnotherAttachmentTest(answer) {
deepEqual(answer, {
"attachment": "ab",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"id": "a",
"method": "putAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Create another attachment");
}
function updateLastDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hey",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
},
"ab": {
"content_type": "text/plain",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"length": 3
}
}
})]); // GET
responses.push([204, {}, '']); // PUT
return jio.put({"_id": "a", "title": "Hoo"});
}
function updateLastDocumentTest(answer) {
deepEqual(answer, {
"id": "a",
"method": "put",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Update document metadata");
}
function getFirstAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
},
"ab": {
"content_type": "text/plain",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"length": 3
}
}
})]); // GET
responses.push([200, {
"Content-Type": "application/octet-stream"
}, "aab"]); // GET
return jio.getAttachment({"_id": "a", "_attachment": "aa"});
}
function getFirstAttachmentTest(answer) {
var blob = answer.data;
answer.data = "<blob>";
deepEqual(answer, {
"attachment": "aa",
"data": "<blob>",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"id": "a",
"method": "getAttachment",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Get first attachment");
return jIO.util.readBlobAsText(blob).then(function (e) {
deepEqual(blob.type, "text/plain", "Check blob type");
deepEqual(e.target.result, "aab", "Check blob text content");
}, function (err) {
deepEqual(err, "no error", "Check blob text content");
});
}
function getSecondAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
},
"ab": {
"content_type": "text/plain",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"length": 3
}
}
})]); // GET
responses.push([200, {
"Content-Type": "application/octet-stream"
}, "aba"]); // GET
return jio.getAttachment({"_id": "a", "_attachment": "ab"});
}
function getSecondAttachmentTest(answer) {
var blob = answer.data;
answer.data = "<blob>";
deepEqual(answer, {
"attachment": "ab",
"data": "<blob>",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"id": "a",
"method": "getAttachment",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Get first attachment");
return jIO.util.readBlobAsText(blob).then(function (e) {
deepEqual(blob.type, "text/plain", "Check blob type");
deepEqual(e.target.result, "aba", "Check blob text content");
}, function (err) {
deepEqual(err, "no error", "Check blob text content");
});
}
function getLastDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
},
"ab": {
"content_type": "text/plain",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"length": 3
}
}
})]); // GET
return jio.get({"_id": "a"});
}
function getLastDocumentTest(answer) {
deepEqual(answer, {
"data": {
"_id": "a",
"title": "Hoo",
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
},
"other": {
"length": 3,
"digest": "md5-dontcare-again",
"content_type": "text/plain"
"ab": {
"content_type": "text/plain",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"length": 3
}
}
})
]
);
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({
},
"id": "a",
"method": "get",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Get last document metadata");
}
function removeSecondAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
},
"ab": {
"content_type": "text/plain",
"digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
"ed343e6c739e54131fcb3a56e4bc1bd",
"length": 3
}
}
})]); // GET
responses.push([204, {}, '']); // PUT
responses.push([204, {}, '']); // DELETE
return jio.removeAttachment({"_id": "a", "_attachment": "ab"});
}
function removeSecondAttachmentTest(answer) {
deepEqual(answer, {
"attachment": "ab",
"id": "a",
"method": "removeAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove second document");
}
function getInexistentSecondAttachment() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5"+
"0728e095ff24218119d51bd22475363",
"length": 3
}
}
})]); // GET
return success(jio.getAttachment({"_id": "a", "_attachment": "ab"}));
}
function getInexistentSecondAttachmentTest(answer) {
deepEqual(answer, {
"attachment": "ab",
"error": "not_found",
"id": "a",
"message": "File does not exist",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get inexistent second attachment");
}
function getOneAttachmentDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
"0728e095ff24218119d51bd22475363",
"length": 3
}
}
})]); // GET
return jio.get({"_id": "a"});
}
function getOneAttachmentDocumentTest(answer) {
deepEqual(answer, {
"data": {
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
},
"other": {
"length": 3,
"digest": "md5-dontcare-again",
"content_type": "text/plain"
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
"0728e095ff24218119d51bd22475363",
"length": 3
}
},
"_id": "a",
"title": "Hoo"
},
"id": "a",
"method": "get",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "Get document metadata");
}
function removeSecondAttachmentAgain() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
"0728e095ff24218119d51bd22475363",
"length": 3
}
}
})]); // GET
return success(jio.removeAttachment({"_id": "a", "_attachment": "ab"}));
}
function removeSecondAttachmentAgainTest(answer) {
deepEqual(answer, {
"attachment": "ab",
"error": "not_found",
"id": "a",
"message": "This Attachment does not exist",
"method": "removeAttachment",
"reason": "missing attachment",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove inexistent attachment");
}
function removeDocument() {
responses.push([200, {
"Content-Type": "application/octet-stream"
}, JSON.stringify({
"_id": "a",
"title": "Hoo",
"_attachments": {
"aa": {
"content_type": "text/plain",
"digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
"0728e095ff24218119d51bd22475363",
"length": 3
}
})
]
);
}
})]); // GET
responses.push([204, {}, '']); // DELETE (metadata)
responses.push([204, {}, '']); // DELETE (attachment aa)
return jio.remove({"_id": "a"});
}
function removeDocumentTest(answer) {
deepEqual(answer, {
"id": "a",
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove document and its attachments");
}
function getInexistentFirstAttachment() {
responses.push([404, {}, '']); // GET
return success(jio.getAttachment({"_id": "a", "_attachment": "aa"}));
}
function getInexistentFirstAttachmentTest(answer) {
deepEqual(answer, {
"attachment": "aa",
"error": "not_found",
"id": "a",
"message": "File does not exist",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get inexistent first attachment");
}
function getInexistentDocument() {
responses.push([404, {}, '']); // GET
return success(jio.get({"_id": "a"}));
}
function getInexistentDocumentTest(answer) {
deepEqual(answer, {
"error": "not_found",
"id": "a",
"message": "File does not exist",
"method": "get",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get inexistent document");
}
function removeInexistentDocument() {
responses.push([404, {}, '']); // GET
return success(jio.remove({"_id": "a"}));
}
function removeInexistentDocumentTest(answer) {
deepEqual(answer, {
"error": "not_found",
"id": "a",
"message": "File does not exist",
"method": "remove",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove already removed document");
}
function unexpectedError(error) {
if (error instanceof Error) {
deepEqual([
error.name + ": " + error.message,
error
], "UNEXPECTED ERROR", "Unexpected error");
} else {
deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
}
}
// # Post new documents, list them and remove them
// post a 201
postNewDocument().then(postNewDocumentTest).
// get 200
then(getCreatedDocument).then(getCreatedDocumentTest).
// post b 201
then(postSpecificDocument).then(postSpecificDocumentTest).
//postSpecificDocument().then(postSpecificDocumentTest).
// allD 200 2 documents
then(listDocuments).then(list2DocumentsTest).
//listDocuments().then(list2DocumentsTest).
// remove a 204
then(removeCreatedDocument).then(removeCreatedDocumentTest).
// remove b 204
then(removeSpecificDocument).then(removeSpecificDocumentTest).
// allD 200 empty storage
then(listEmptyStorage).then(listEmptyStorageTest).
// # 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).
always(server.restore.bind(server));
});
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();
module("SplitStorage + S3 Storage");
util.closeAndcleanUpJio(o.jio);
});
}));
}());
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, test_util, RSVP, test, ok, deepEqual, module, stop,
start, hex_sha256 */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, test_util, RSVP);
}([
'jio',
'test_util',
'rsvp',
's3storage',
'splitstorage'
], function (jIO, util, RSVP) {
"use strict";
var tool = {
"readBlobAsBinaryString": jIO.util.readBlobAsBinaryString
};
function reverse(promise) {
return new RSVP.Promise(function (resolve, reject, notify) {
promise.then(reject, resolve, notify);
}, function () {
promise.cancel();
});
}
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called
* with no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
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) {
if (Array.isArray(thens[i])) {
promises[i + 1] = promises[i].
then(thens[i][0], thens[i][1], thens[i][2]);
} else {
promises[i + 1] = promises[i].then(thens[i]);
}
}
promises[i].then(resolve, reject, notify);
}, function () {
var i;
for (i = 0; i < promises.length; i += 1) {
promises[i].cancel();
}
});
}
function unexpectedError(error) {
if (error instanceof Error) {
deepEqual([
error.name + ": " + error.message,
error
], "UNEXPECTED ERROR", "Unexpected error");
} else {
deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
}
}
module("SplitStorage + S3 Storage");
test("Post", function () {
var shared = {}, jio, jio_s3_list = [];
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
jio_s3_list[0] = jIO.createJIO(shared.s3_storage_description1, {
"workspace": shared.workspace
});
jio_s3_list[1] = jIO.createJIO(shared.s3_storage_description2, {
"workspace": shared.workspace
});
jio_s3_list.run = function (method, argument) {
var i, promises = [];
for (i = 0; i < this.length; i += 1) {
promises[i] = this[i][method].apply(this[i], argument);
}
return RSVP.all(promises);
};
jio_s3_list.get = function () {
return this.run("get", arguments);
};
stop();
// post without id
jio.post({
"_underscored_meta": "uvalue",
"meta": "data"
})
.then(function (answer) {
shared.uuid = answer.id;
answer.id = "<uuid>";
ok(util.isUuid(shared.uuid), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + shared.uuid);
deepEqual(answer, {
"id": "<uuid>",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post document without id");
// check uploaded documents
return jio_s3_list.get({"_id": shared.uuid});
})
.then(function (answers) {
var i;
for (i = 0; i < answers.length; i += 1) {
deepEqual(answers[i].data, {
"_id": shared.uuid,
"_underscored_meta": "uvalue",
"data": i === 0 ? "{\"meta\"" : ":\"data\"}"
}, "Check uploaded document in sub storage " + (i + 1));
}
// post with id
return jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
});
})
.then(function (answer) {
deepEqual(answer, {
"id": "one",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post document with id");
// check uploaded documents
return jio_s3_list.get({"_id": "one"});
})
.then(function (answers) {
deepEqual(answers[0].data, {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "{\"meta\":\"data\","
}, "Check uploaded document in sub storage 1");
deepEqual(answers[1].data, {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "\"hello\":\"world\"}"
}, "Check uploaded document in sub storage 2");
// post with id
return reverse(jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
}));
})
.then(function (answer) {
deepEqual(answer, {
"error": "conflict",
"id": "one",
"message": "Unable to post document",
"method": "post",
"reason": "Document already exists",
"result": "error",
"status": 409,
"statusText": "Conflict"
}, "Post document with same id -> 409 Conflict");
})
.fail(unexpectedError).always(start);
});
test("PutAttachment", function () {
var shared = {}, jio, jio_s3_list = [];
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "putAttachment1",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "putAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
jio_s3_list[0] = jIO.createJIO(shared.s3_storage_description1, {
"workspace": shared.workspace
});
jio_s3_list[1] = jIO.createJIO(shared.s3_storage_description2, {
"workspace": shared.workspace
});
jio_s3_list.run = function (method, argument) {
var i, promises = [];
for (i = 0; i < this.length; i += 1) {
promises[i] = this[i][method].apply(this[i], argument);
}
return RSVP.all(promises);
};
jio_s3_list.get = function () {
return this.run("get", arguments);
};
jio_s3_list.getAttachmentAsBinaryString = function () {
return this.run("getAttachment", arguments).then(function (answers) {
var i, promises = [];
for (i = 0; i < answers.length; i += 1) {
promises[i] = tool.readBlobAsBinaryString(answers[i].data);
}
return RSVP.all(promises);
});
};
stop();
return reverse(jio.putAttachment({
"_id": "two",
"_attachment": "my_attachment",
"_data": "My Data",
"_content_type": "text/plain"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "two",
"message": "Unable to put attachment",
"method": "putAttachment",
"reason": "Document does not exist",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Put attachment on a inexistent document -> 404 Not Found");
return jio.post({
"_id": "two",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.putAttachment({
"_id": "two",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"id": "two",
"method": "putAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put attachment on a document");
// check uploaded documents
return jio_s3_list.get({"_id": "two"});
}).then(function (answers) {
deepEqual(answers[0].data, {
"_attachments": {
"my_attachment": {
"content_type": "text/plain",
"digest": "sha256-ebf2d770a6a2dfa135f6c81431f22fc3cbcde9ae" +
"e52759ca9e520d4d964c1322", // sha256("My ")
"length": 3
}
},
"_id": "two",
"_underscored_meta": "uvalue",
"data": "{\"meta\""
}, "Check uploaded document in sub storage 1");
deepEqual(answers[1].data, {
"_attachments": {
"my_attachment": {
"content_type": "text/plain",
"digest": "sha256-cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b" +
"3cdf79496dc442d52b8dd528", // sha256("Data")
"length": 4
}
},
"_id": "two",
"_underscored_meta": "uvalue",
"data": ":\"data\"}"
}, "Check uploaded document in sub storage 2");
return jio_s3_list.getAttachmentAsBinaryString({
"_id": "two",
"_attachment": "my_attachment"
});
}).then(function (events) {
deepEqual(events[0].target.result, "My ",
"Check uploaded document in sub storage 1");
deepEqual(events[1].target.result, "Data",
"Check uploaded document in sub storage 1");
}).fail(unexpectedError).always(start);
});
test("Get", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "get1",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "get2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.get({"_id": "three"})).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "three",
"message": "Unable to get document",
"method": "get",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get missing document");
return jio.post({
"_id": "three",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.get({"_id": "three"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "three",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Get posted document");
return jio.putAttachment({
"_id": "three",
"_attachment": "my_attachment",
"_data": "My Data",
"_content_type": "text/plain"
});
}).then(function () {
return jio.get({"_id": "three"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "three",
"_underscored_meta": "uvalue",
"meta": "data",
"_attachments": {
"my_attachment": {
"length": 7,
"content_type": "text/plain"
}
}
}, "Get document with attachment informations");
}).fail(unexpectedError).always(start);
});
test("GetAttachment", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "getAttachment",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"application_name": "getAttachment2",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.getAttachment({
"_id": "four",
"_attachment": "my_attachment"
}))
.then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "four",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get attachment from missing document -> 404 Not Found");
return jio.post({
"_id": "four",
"_underscored_meta": "uvalue",
"meta": "data"
});
})
.then(function () {
return reverse(jio.getAttachment({
"_id": "four",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "four",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Get missing attachment from document");
return jio.putAttachment({
"_id": "four",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
})
.then(function () {
return jio.getAttachment({
"_id": "four",
"_attachment": "my_attachment"
});
}).then(function (answer) {
return tool.readBlobAsBinaryString(answer.data);
}).then(function (event) {
deepEqual(event.target.result, "My Data", "Get attachment");
})
.fail(unexpectedError).always(start);
});
test("RemoveAttachment", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"mode": "memory"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
"mode": "memory"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.removeAttachment({
"_id": "five",
"_attachment": "my_attachment"
})).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "five",
"message": "Unable to remove attachment",
"method": "removeAttachment",
"reason": "missing document",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove attachment from inexistent document -> 404 Not Found");
return jio.post({
"_id": "five",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return reverse(jio.removeAttachment({
"_id": "five",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "five",
"message": "Unable to remove attachment",
"method": "removeAttachment",
"reason": "missing attachment",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove inexistent attachment -> 404 Not Found");
return jio.putAttachment({
"_id": "five",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
})
.then(function () {
return jio.removeAttachment({
"_id": "five",
"_attachment": "my_attachment"
});
})
.then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"id": "five",
"method": "removeAttachment",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove attachment");
return jio.get({"_id": "five"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "five",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Check document");
return reverse(jio.getAttachment({
"_id": "five",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "five",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check attachment -> 404 Not Found");
})
.fail(unexpectedError).always(start);
});
test("Remove", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
reverse(jio.remove({"_id": "six"})).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "six",
"message": "Unable to remove document",
"method": "remove",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Remove missing document -> 404 Not Found");
return jio.post({
"_id": "six",
"_underscored_meta": "uvalue",
"meta": "data"
});
}).then(function () {
return jio.putAttachment({
"_id": "six",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
}).then(function () {
return jio.remove({"_id": "six"});
}).then(function (answer) {
deepEqual(answer, {
"id": "six",
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove document");
return reverse(jio.getAttachment({
"_id": "six",
"_attachment": "my_attachment"
}));
}).then(function (answer) {
deepEqual(answer, {
"attachment": "my_attachment",
"error": "not_found",
"id": "six",
"message": "Unable to get attachment",
"method": "getAttachment",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check attachment -> 404 Not Found");
return reverse(jio.get({"_id": "six"}));
}).then(function (answer) {
deepEqual(answer, {
"error": "not_found",
"id": "six",
"message": "Unable to get document",
"method": "get",
"reason": "Not Found",
"result": "error",
"status": 404,
"statusText": "Not Found"
}, "Check document -> 404 Not Found");
}).fail(unexpectedError).always(start);
});
test("Put", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucketsplit",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucketsplit_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
jio.put({
"_id": "seven",
"_underscored_meta": "uvalue",
"meta": "data"
}).then(function (answer) {
deepEqual(answer, {
"id": "seven",
"method": "put",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put new document");
return jio.get({"_id": "seven"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "seven",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Check document");
return jio.put({
"_id": "seven",
"_underscored_meta": "uvalue",
"meow": "dog"
});
}).then(function (answer) {
deepEqual(answer, {
"id": "seven",
"method": "put",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Put same document again");
return jio.get({"_id": "seven"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "seven",
"_underscored_meta": "uvalue",
"meow": "dog"
}, "Get document for check");
}).fail(unexpectedError).always(start);
});
test("AllDocs", function () {
var shared = {}, jio;
shared.workspace = {};
shared.s3_storage_description1 = {
"type": "s3",
"server": "jiobucket_alldocs",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
shared.s3_storage_description2 = {
"type": "s3",
"server": "jiobucket_alldocs_bis",
"AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
"password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
};
jio = jIO.createJIO({
"type": "split",
"storage_list": [
shared.s3_storage_description1,
shared.s3_storage_description2
]
}, {"workspace": shared.workspace});
stop();
function prepareDatabase() {
var i, do_list = [];
function post(i) {
return function () {
return jio.post({
"_id": "doc" + i,
"_underscored_meta": "uvalue" + i,
"meta": "data" + i
});
};
}
function putAttachment(i) {
return function () {
return jio.putAttachment({
"_id": "doc" + i,
"_attachment": "my_attachment" + i,
"_data": "My Data" + i,
"_content_type": "text/plain"
});
};
}
for (i = 0; i < 5; i += 1) {
do_list.push(post(i));
}
for (i = 0; i < 2; i += 1) {
do_list.push(putAttachment(i));
}
return sequence(do_list);
}
prepareDatabase().then(function () {
return jio.get({"_id": "doc1"});
}).then(function (answer) {
deepEqual(answer.data, {
"_id": "doc1",
"_underscored_meta": "uvalue1",
"meta": "data1",
"_attachments": {
"my_attachment1": {
"length": 8,
"content_type": "text/plain"
}
}
}, "Check document");
return jio.allDocs();
}).then(function (answer) {
answer.data.rows.sort(function (a, b) {
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
});
deepEqual(answer.data, {
"total_rows": 5,
"rows": [
{
"id": "doc0",
"value": {}
},
{
"id": "doc1",
"value": {}
},
{
"id": "doc2",
"value": {}
},
{
"id": "doc3",
"value": {}
},
{
"id": "doc4",
"value": {}
}]
}, "AllDocs with document ids only");
}).fail(unexpectedError).always(start);
});
}));
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