Commit bb18e075 authored by Romain Courteaud's avatar Romain Courteaud 🐸

Activate IndexedDB storage.

Simplify storage and tests code.

Change the database structure so that the "attachment" store contains one entry per attachment.
parent 19cff054
......@@ -179,6 +179,7 @@ module.exports = function (grunt) {
'src/jio.storage/querystorage.js',
'src/jio.storage/drivetojiomapping.js',
'src/jio.storage/documentstorage.js',
'src/jio.storage/indexeddbstorage.js'
],
dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
// dest: 'jio.js'
......
......@@ -13,8 +13,7 @@
*
* {
* "type": "indexeddb",
* "database": <string>,
* "unite": <integer> //byte
* "database": <string>
* }
*
* The database name will be prefixed by "jio:", so if the database property is
......@@ -28,748 +27,389 @@
* - https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB
*/
/*jslint indent: 2, maxlen: 120, nomen: true */
/*jslint nomen: true */
/*global indexedDB, jIO, RSVP, Blob, Math*/
(function (jIO) {
(function (indexedDB, jIO, RSVP, Blob, Math) {
"use strict";
var generateUuid = jIO.util.generateUuid;
// Read only as changing it can lead to data corruption
var UNITE = 2000000;
function metadataObjectToString(value) {
var i, l;
if (Array.isArray(value)) {
for (i = 0, l = value.length; i < l; i += 1) {
value[i] = metadataObjectToString(value[i]);
}
return value;
}
if (typeof value === "object" && value !== null) {
return value.content;
}
return value;
}
/**
* new IndexedDBStorage(description)
*
* Creates a storage object designed for jIO to store documents into
* indexedDB.
*
* @class IndexedDBStorage
* @constructor
*/
function IndexedDBStorage(description) {
if (typeof description.database !== "string" ||
description.database === "") {
throw new TypeError("IndexedDBStorage 'database' description property " +
"must be a non-empty string");
}
if (description.unite !== undefined) {
if (description.unite !== parseInt(description.unite, 10)) {
throw new TypeError("IndexedDBStorage 'unite' description property " +
"must be a integer");
}
} else {
description.unite = 2000000;
}
this._database_name = "jio:" + description.database;
this._unite = description.unite;
}
IndexedDBStorage.prototype.hasCapacity = function (name) {
return (name === "list");
};
/**
* creat 3 objectStores
* @param {string} the name of the database
*/
function openIndexedDB(db_name) {
var request;
function resolver(resolve, reject) {
// Open DB //
request = indexedDB.open(db_name);
request.onerror = reject;
function buildKeyPath(key_list) {
return key_list.join("_");
}
// Create DB if necessary //
request.onupgradeneeded = function (evt) {
function handleUpgradeNeeded(evt) {
var db = evt.target.result,
store;
store = db.createObjectStore("metadata", {
"keyPath": "_id"
//"autoIncrement": true
keyPath: "_id",
autoIncrement: false
});
store.createIndex("_id", "_id");
// It is not possible to use openKeyCursor on keypath directly
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=19955
store.createIndex("_id", "_id", {unique: true});
store = db.createObjectStore("attachment", {
"keyPath": "_id"
//"autoIncrement": true
keyPath: "_key_path",
autoIncrement: false
});
store.createIndex("_id", "_id");
store.createIndex("_id", "_id", {unique: false});
store = db.createObjectStore("blob", {
"keyPath": ["_id", "_attachment", "_part"]
//"autoIncrement": true
keyPath: "_key_path",
autoIncrement: false
});
store.createIndex("_id_attachment_part",
["_id", "_attachment", "_part"]);
};
request.onsuccess = function () {
resolve(request.result);
};
}
return new RSVP.Promise(resolver);
store.createIndex("_id_attachment",
["_id", "_attachment"], {unique: false});
store.createIndex("_id", "_id", {unique: false});
}
/**
*put a data into a store object
*@param {ObjectStore} store The objectstore
*@param {Object} metadata The data to put in
*@return a new promise
*/
function putIndexedDBArrayBuffer(store, metadata) {
var request,
resolver;
request = store.put(metadata);
resolver = function (resolve, reject) {
request.onerror = function (e) {
reject(e);
};
request.onsuccess = function () {
resolve(metadata);
};
};
return new RSVP.Promise(resolver);
function openIndexedDB(jio_storage) {
var db_name = jio_storage._database_name;
function resolver(resolve, reject) {
// Open DB //
var request = indexedDB.open(db_name);
request.onerror = function (error) {
if (request.result) {
request.result.close();
}
function putIndexedDB(store, metadata, readData) {
var request,
resolver;
try {
request = store.put(metadata);
resolver = function (resolve, reject) {
request.onerror = function (e) {
reject(e);
};
request.onsuccess = function () {
resolve(metadata);
reject(error);
};
};
return new RSVP.Promise(resolver);
} catch (e) {
return putIndexedDBArrayBuffer(store,
{"_id" : metadata._id,
"_attachment" : metadata._attachment,
"_part" : metadata._part,
"blob": readData});
}
}
function transactionEnd(transaction) {
var resolver;
resolver = function (resolve, reject) {
transaction.onabort = reject;
transaction.oncomplete = function () {
resolve("end");
request.onabort = function () {
request.result.close();
reject("Aborting connection to: " + db_name);
};
request.ontimeout = function () {
request.result.close();
reject("Connection to: " + db_name + " timeout");
};
return new RSVP.Promise(resolver);
}
/**
* get a data from a store object
* @param {ObjectStore} store The objectstore
* @param {String} id The data id
* return a new promise
*/
function getIndexedDB(store, id) {
function resolver(resolve, reject) {
var request = store.get(id);
request.onerror = reject;
request.onsuccess = function () {
resolve(request.result);
request.onblocked = function () {
request.result.close();
reject("Connection to: " + db_name + " was blocked");
};
}
return new RSVP.Promise(resolver);
}
/**
* delete a data of a store object
* @param {ObjectStore} store The objectstore
* @param {String} id The data id
* @return a new promise
*
*/
function removeIndexedDB(store, id) {
function resolver(resolve, reject) {
var request = store["delete"](id);
request.onerror = function (e) {
reject(e);
// Create DB if necessary //
request.onupgradeneeded = handleUpgradeNeeded;
request.onversionchange = function () {
request.result.close();
reject(db_name + " was upgraded");
};
request.onsuccess = function () {
resolve(request.result);
};
}
// XXX Canceller???
return new RSVP.Queue()
.push(function () {
return new RSVP.Promise(resolver);
});
}
/**
* research an id in a store
* @param {ObjectStore} store The objectstore
* @param {String} id The index id
* @param {var} researchID The data id
* return a new promise
*/
function researchIndexedDB(store, id, researchID) {
function resolver(resolve) {
var index = store.index(researchID);
index.get(id).onsuccess = function (evt) {
resolve({"result" : evt.target.result, "store": store});
function openTransaction(db, stores, flag, autoclosedb) {
var tx = db.transaction(stores, flag);
if (autoclosedb !== false) {
tx.oncomplete = function () {
db.close();
};
}
return new RSVP.Promise(resolver);
tx.onabort = function () {
db.close();
};
return tx;
}
function promiseResearch(transaction, id, table, researchID) {
var store = transaction.objectStore(table);
return researchIndexedDB(store, id, researchID);
function handleCursor(request, callback) {
function resolver(resolve, reject) {
// Open DB //
request.onerror = function (error) {
if (request.transaction) {
request.transaction.abort();
}
reject(error);
};
/**
* put or post a metadata into objectstore:metadata,attachment
* @param {function} open The function to open a basedata
* @param {function} research The function to reserach
* @param {function} ongoing The function to process
* @param {function} end The completed function
* @param {Object} metadata The data to put
*/
IndexedDBStorage.prototype._putOrPost =
function (open, research, ongoing, end, metadata) {
var jio_storage = this,
transaction,
global_db,
result;
return new RSVP.Queue()
.push(function () {
//open a database
return open(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["metadata",
"attachment"], "readwrite");
//research in metadata
return research(transaction, metadata._id, "metadata", "_id");
})
.push(function (researchResult) {
return ongoing(researchResult);
})
.push(function (ongoingResult) {
//research in attachment
result = ongoingResult;
return research(transaction, metadata._id, "attachment", "_id");
})
.push(function (researchResult) {
//create an id in attachment si necessary
if (researchResult.result === undefined) {
return putIndexedDB(researchResult.store, {"_id": metadata._id});
request.onsuccess = function (evt) {
var cursor = evt.target.result;
if (cursor) {
// XXX Wait for result
try {
callback(cursor);
} catch (error) {
reject(error);
}
})
.push(function () {
return transactionEnd(transaction);
})
.push(function () {
return end(result);
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
// continue to next iteration
cursor["continue"]();
} else {
resolve();
}
throw error;
});
};
/**
* Retrieve data
*
*@param {Object} param The command parameters
*/
IndexedDBStorage.prototype.get = function (param) {
var jio_storage = this,
transaction,
global_db,
meta;
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["metadata", "attachment"], "readonly");
var store = transaction.objectStore("metadata");
return getIndexedDB(store, param._id);
})
.push(function (result) {
if (result) {
//get a part data from metadata
meta = result;
var store = transaction.objectStore("attachment");
return getIndexedDB(store, param._id);
}
throw new jIO.util.jIOError("Cannot find document", 404);
})
.push(function (result) {
//get the reste data from attachment
if (result._attachment) {
meta._attachments = result._attachment;
}
return transactionEnd(transaction);
})
.push(function () {
return meta;
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
// XXX Canceller???
return new RSVP.Promise(resolver);
}
throw error;
});
};
IndexedDBStorage.prototype.buildQuery = function () {
var result_list = [];
/**
* Remove a document
*
* @param {Object} param The command parameters
*/
IndexedDBStorage.prototype.remove = function (param) {
var jio_storage = this,
transaction,
global_db,
queue = new RSVP.Queue();
function removeAllPart(store, attachment, part, totalLength) {
if (part * jio_storage._unite >= totalLength) {
return;
}
return removeIndexedDB(store, [param._id, attachment, part])
.then(function () {
return removeAllPart(store, attachment, part + 1, totalLength);
});
}
function removeAll(store, array, index, allAttachment) {
var totalLength = allAttachment[array[index]].length;
return removeAllPart(store, array[index], 0, totalLength)
.then(function () {
if (index < array.length - 1) {
return removeAll(store, array, index + 1, allAttachment);
}
function pushMetadata(cursor) {
result_list.push({
"id": cursor.key,
"value": {}
});
}
return queue.push(function () {
return openIndexedDB(jio_storage._database_name);
})
return openIndexedDB(this)
.push(function (db) {
global_db = db;
transaction = db.transaction(["metadata",
"attachment", "blob"], "readwrite");
return promiseResearch(transaction, param._id, "metadata", "_id");
})
.push(function (resultResearch) {
if (resultResearch.result === undefined) {
throw new jIO.util.jIOError("IndexeddbStorage, unable to get metadata.", 500);
}
//delete metadata
return removeIndexedDB(resultResearch.store, param._id);
var tx = openTransaction(db, ["metadata"], "readonly");
return handleCursor(tx.objectStore("metadata").index("_id")
.openKeyCursor(), pushMetadata);
})
.push(function () {
var store = transaction.objectStore("attachment");
return getIndexedDB(store, param._id);
})
.push(function (result) {
if (result._attachment) {
var array, store;
array = Object.keys(result._attachment);
store = transaction.objectStore("blob");
return removeAll(store, array, 0, result._attachment);
}
})
.push(function () {
var store = transaction.objectStore("attachment");
//delete attachment
return removeIndexedDB(store, param._id);
})
.push(function () {
return transactionEnd(transaction);
})
.push(function () {
return ({"status": 204});
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
return result_list;
});
};
};
/**
* Creates a new document if not already existes
* @param {Object} metadata The metadata to put
*/
IndexedDBStorage.prototype.post = function (metadata) {
var that = this;
if (!metadata._id) {
metadata._id = generateUuid();
function handleGet(request) {
function resolver(resolve, reject) {
request.onerror = reject;
request.onsuccess = function () {
if (request.result) {
resolve(request.result);
}
function promiseOngoingPost(researchResult) {
if (researchResult.result === undefined) {
delete metadata._attachment;
return putIndexedDB(researchResult.store, metadata);
// XXX How to get ID
reject(new jIO.util.jIOError("Cannot find document", 404));
};
}
throw ({"status": 409, "reason": "Document exists"});
return new RSVP.Promise(resolver);
}
function promiseEndPost(metadata) {
return metadata._id;
IndexedDBStorage.prototype.get = function (param) {
var attachment_dict = {};
function addEntry(cursor) {
attachment_dict[cursor.value._attachment] = {};
}
return that._putOrPost(openIndexedDB, promiseResearch,
promiseOngoingPost, promiseEndPost,
metadata);
return openIndexedDB(this)
.push(function (db) {
var transaction = openTransaction(db, ["metadata", "attachment"],
"readonly");
return RSVP.all([
handleGet(transaction.objectStore("metadata").get(param._id)),
handleCursor(transaction.objectStore("attachment").index("_id")
.openCursor(), addEntry)
]);
})
.push(function (result_list) {
var result = result_list[0];
if (Object.getOwnPropertyNames(attachment_dict).length > 0) {
result._attachments = attachment_dict;
}
return result;
});
};
function handleRequest(request) {
function resolver(resolve, reject) {
request.onerror = reject;
request.onsuccess = function () {
resolve(request.result);
};
/**
* Creates or updates a document
* @param {Object} metadata The metadata to post
*/
IndexedDBStorage.prototype.put = function (metadata) {
var that = this;
function promiseOngoingPut(researchResult) {
var key;
for (key in metadata) {
if (metadata.hasOwnProperty(key)) {
metadata[key] = metadataObjectToString(metadata[key]);
}
}
delete metadata._attachment;
return putIndexedDB(researchResult.store, metadata);
return new RSVP.Promise(resolver);
}
function promiseEndPut() {
return metadata._id;
}
return that._putOrPost(openIndexedDB, promiseResearch,
promiseOngoingPut, promiseEndPut,
metadata);
IndexedDBStorage.prototype.put = function (metadata) {
return openIndexedDB(this)
.push(function (db) {
var transaction = openTransaction(db, ["metadata"], "readwrite");
return handleRequest(transaction.objectStore("metadata").put(metadata));
});
};
/**
* Add an attachment to a document
*
* @param {Object} metadata The data
*
*/
IndexedDBStorage.prototype.putAttachment = function (metadata) {
var jio_storage = this,
transaction,
global_db,
BlobInfo,
readResult;
function putAllPart(store, metadata, readResult, count, part) {
var blob,
readPart,
end;
if (count >= metadata._blob.size) {
return;
function deleteEntry(cursor) {
cursor["delete"]();
}
end = count + jio_storage._unite;
blob = metadata._blob.slice(count, end);
readPart = readResult.slice(count, end);
return putIndexedDB(store, {"_id": metadata._id,
"_attachment" : metadata._attachment,
"_part" : part,
"blob": blob}, readPart)
.then(function () {
return putAllPart(store, metadata, readResult, end, part + 1);
});
}
return jIO.util.readBlobAsArrayBuffer(metadata._blob)
.then(function (event) {
readResult = event.target.result;
BlobInfo = {
"content_type": metadata._blob.type,
"length": metadata._blob.size
};
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
IndexedDBStorage.prototype.remove = function (param) {
return openIndexedDB(this)
.push(function (db) {
global_db = db;
transaction = db.transaction(["attachment",
var transaction = openTransaction(db, ["metadata", "attachment",
"blob"], "readwrite");
return promiseResearch(transaction,
metadata._id, "attachment", "_id");
})
.push(function (researchResult) {
if (researchResult.result === undefined) {
throw new jIO.util.jIOError("IndexeddbStorage unable to put attachment.", 500);
}
//update attachment
researchResult.result._attachment = researchResult.
result._attachment || {};
researchResult.result._attachment[metadata._attachment] =
(BlobInfo === undefined) ? "BlobInfo" : BlobInfo;
return putIndexedDB(researchResult.store, researchResult.result);
})
.push(function () {
//put in blob
var store = transaction.objectStore("blob");
return putAllPart(store, metadata, readResult, 0, 0);
})
.push(function () {
return transactionEnd(transaction);
})
// .push(function () {
// return {"status": 204};
// })
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
});
return RSVP.all([
handleRequest(transaction
.objectStore("metadata")["delete"](param._id)),
// XXX Why not possible to delete with KeyCursor?
handleCursor(transaction.objectStore("attachment").index("_id")
.openCursor(), deleteEntry),
handleCursor(transaction.objectStore("blob").index("_id")
.openCursor(), deleteEntry)
]);
});
};
/**
* Retriev a document attachment
*
* @param {Object} param The command parameter
*/
IndexedDBStorage.prototype.getAttachment = function (param) {
var jio_storage = this,
transaction,
global_db,
blob,
totalLength;
function getDesirePart(store, start, end) {
if (start > end) {
return;
}
return getIndexedDB(store, [param._id, param._attachment, start])
.then(function (result) {
var blobPart = result.blob;
if (result.blob.byteLength !== undefined) {
blobPart = new Blob([result.blob]);
}
if (blob) {
blob = new Blob([blob, blobPart]);
} else {
blob = blobPart;
}
return getDesirePart(store, start + 1, end);
});
}
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["attachment", "blob"], "readwrite");
//check if the attachment exists
return promiseResearch(transaction,
param._id, "attachment", "_id");
})
.push(function (researchResult) {
var result = researchResult.result,
var transaction,
start,
end;
if (result === undefined ||
result._attachment[param._attachment] === undefined) {
throw new jIO.util.jIOError("IndexeddbStorage unable to get attachment.", 404);
}
totalLength = result._attachment[param._attachment].length;
param._start = param._start === undefined ? 0 : param._start;
param._end = param._end === undefined ? totalLength
: param._end;
if (param._end > totalLength) {
param._end = totalLength;
}
if (param._start < 0 || param._end < 0) {
throw ({"status": 404, "reason": "invalide _start, _end",
"message": "_start and _end must be positive"});
}
if (param._start > param._end) {
throw ({"status": 404, "reason": "invalide offset",
"message": "start is great then end"});
}
start = Math.floor(param._start / jio_storage._unite);
end = Math.floor(param._end / jio_storage._unite);
if (param._end % jio_storage._unite === 0) {
end -= 1;
}
return getDesirePart(transaction.objectStore("blob"),
start,
end);
})
.push(function () {
var start = param._start % jio_storage._unite,
end = start + param._end - param._start;
blob = blob.slice(start, end);
return new Blob([blob], {type: "text/plain"});
return openIndexedDB(this)
.push(function (db) {
transaction = openTransaction(db, ["attachment", "blob"], "readonly");
// XXX Should raise if key is not good
return handleGet(transaction.objectStore("attachment")
.get(buildKeyPath([param._id, param._attachment])));
})
.push(undefined, function (error) {
// Check if transaction is ongoing, if so, abort it
if (transaction !== undefined) {
transaction.abort();
.push(function (attachment) {
var total_length = attachment.info.length,
i,
promise_list = [],
store = transaction.objectStore("blob"),
start_index,
end_index;
start = param._start || 0;
end = param._end || total_length;
if (end > total_length) {
end = total_length;
}
if (global_db !== undefined) {
global_db.close();
if (start < 0 || end < 0) {
throw new jIO.util.jIOError("_start and _end must be positive",
400);
}
if (start > end) {
throw new jIO.util.jIOError("_start is greater than _end",
400);
}
throw error;
});
};
start_index = Math.floor(start / UNITE);
end_index = Math.floor(end / UNITE);
if (end % UNITE === 0) {
end_index -= 1;
}
/**
* Remove an attachment
*
* @method removeAttachment
* @param {Object} param The command parameters
*/
IndexedDBStorage.prototype.removeAttachment = function (param) {
var jio_storage = this,
transaction,
global_db,
totalLength;
function removePart(store, part) {
if (part * jio_storage._unite >= totalLength) {
return;
}
return removeIndexedDB(store, [param._id, param._attachment, part])
.then(function () {
return removePart(store, part + 1);
});
for (i = start_index; i <= end_index; i += 1) {
promise_list.push(
handleGet(store.get(buildKeyPath([param._id,
param._attachment, i])))
);
}
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["attachment", "blob"], "readwrite");
//check if the attachment exists
return promiseResearch(transaction, param._id,
"attachment", "_id");
})
.push(function (researchResult) {
var result = researchResult.result;
if (result === undefined ||
result._attachment[param._attachment] === undefined) {
throw ({"status": 404, "reason": "missing attachment",
"message":
"IndexeddbStorage, document attachment not found."});
}
totalLength = result._attachment[param._attachment].length;
//updata attachment
delete result._attachment[param._attachment];
return putIndexedDB(researchResult.store, result);
return RSVP.all(promise_list);
})
.push(function () {
var store = transaction.objectStore("blob");
return removePart(store, 0);
})
.push(function () {
return transactionEnd(transaction);
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
.push(function (result_list) {
var array_buffer_list = [],
blob,
i,
len = result_list.length;
for (i = 0; i < len; i += 1) {
array_buffer_list.push(result_list[i].blob);
}
throw error;
blob = new Blob(array_buffer_list, {type: "application/octet-stream"});
return {data: blob.slice(start, end)};
});
};
function removeAttachment(transaction, param) {
return RSVP.all([
// XXX How to get the right attachment
handleRequest(transaction.objectStore("attachment")["delete"](
buildKeyPath([param._id, param._attachment])
)),
handleCursor(transaction.objectStore("blob").index("_id_attachment")
.openCursor(), deleteEntry)
]);
}
IndexedDBStorage.prototype.hasCapacity = function (name) {
return (name === "list");
};
IndexedDBStorage.prototype.putAttachment = function (metadata) {
var blob_part = [],
transaction,
db;
IndexedDBStorage.prototype.buildQuery = function () {
var jio_storage = this,
global_db;
return openIndexedDB(this)
.push(function (database) {
db = database;
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
// Split the blob first
return jIO.util.readBlobAsArrayBuffer(metadata._blob);
})
.push(function (db) {
global_db = db;
var onCancel;
return new RSVP.Promise(function (resolve, reject) {
var rows = [], open_req = indexedDB.open(jio_storage._database_name);
open_req.onerror = function () {
if (open_req.result) { open_req.result.close(); }
reject(open_req.error);
};
open_req.onsuccess = function () {
var tx, index_req, db = open_req.result;
try {
tx = db.transaction(["metadata"], "readonly");
onCancel = function () {
tx.abort();
db.close();
};
index_req = tx.objectStore("metadata").index("_id").openCursor();
index_req.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
rows.push({
"id": cursor.value._id,
"value": {}
});
.push(function (event) {
var array_buffer = event.target.result,
total_size = metadata._blob.size,
handled_size = 0;
// continue to next iteration
cursor["continue"]();
} else {
db.close();
resolve(rows);
while (handled_size < total_size) {
blob_part.push(array_buffer.slice(handled_size,
handled_size + UNITE));
handled_size += UNITE;
}
};
} catch (e) {
reject(e);
db.close();
// Remove previous attachment
transaction = openTransaction(db, ["attachment", "blob"], "readwrite");
return removeAttachment(transaction, metadata);
})
.push(function () {
var promise_list = [
handleRequest(transaction.objectStore("attachment").put({
"_key_path": buildKeyPath([metadata._id, metadata._attachment]),
"_id": metadata._id,
"_attachment": metadata._attachment,
"info": {
"content_type": metadata._blob.type,
"length": metadata._blob.size
}
};
}, function () {
if (typeof onCancel === "function") {
onCancel();
}))
],
len = blob_part.length,
blob_store = transaction.objectStore("blob"),
i;
for (i = 0; i < len; i += 1) {
promise_list.push(
handleRequest(blob_store.put({
"_key_path": buildKeyPath([metadata._id, metadata._attachment,
i]),
"_id" : metadata._id,
"_attachment" : metadata._attachment,
"_part" : i,
"blob": blob_part[i]
}))
);
}
// Store all new data
return RSVP.all(promise_list);
});
};
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
IndexedDBStorage.prototype.removeAttachment = function (param) {
return openIndexedDB(this)
.push(function (db) {
var transaction = openTransaction(db, ["attachment", "blob"],
"readwrite");
return removeAttachment(transaction, param);
});
};
jIO.addStorage("indexeddb", IndexedDBStorage);
}(jIO));
}(indexedDB, jIO, RSVP, Blob, Math));
/*jslint maxlen: 120, nomen: true */
/*global indexedDB, test_util, console, Blob, sinon*/
(function (jIO, QUnit) {
/*jslint nomen: true */
/*global indexedDB, Blob, sinon, IDBDatabase,
IDBTransaction, IDBIndex, IDBObjectStore, IDBCursor*/
(function (jIO, QUnit, indexedDB, Blob, sinon, IDBDatabase,
IDBTransaction, IDBIndex, IDBObjectStore, IDBCursor) {
"use strict";
var test = QUnit.test,
stop = QUnit.stop,
......@@ -9,26 +11,364 @@
expect = QUnit.expect,
deepEqual = QUnit.deepEqual,
equal = QUnit.equal,
module = QUnit.module;
module = QUnit.module,
big_string = "",
j;
module("indexeddbStorage", {
for (j = 0; j < 3000000; j += 1) {
big_string += "a";
}
function deleteIndexedDB(storage) {
return new RSVP.Queue()
.push(function () {
function resolver(resolve, reject) {
var request = indexedDB.deleteDatabase(
storage.__storage._database_name
);
request.onerror = reject;
request.onblocked = reject;
request.onsuccess = resolve;
}
return new RSVP.Promise(resolver);
});
}
/////////////////////////////////////////////////////////////////
// indexeddbStorage.constructor
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.constructor");
test("default unite value", function () {
var jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
equal(jio.__type, "indexeddb");
deepEqual(jio.__storage._database_name, "jio:qunit");
});
/////////////////////////////////////////////////////////////////
// documentStorage.hasCapacity
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.hasCapacity");
test("can list documents", function () {
var jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
ok(jio.hasCapacity("list"));
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.buildQuery
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.buildQuery", {
setup: function () {
// localStorage.clear();
this.jio = jIO.createJIO({
"type": "indexeddb",
"database": "qunit"
type: "indexeddb",
database: "qunit"
});
this.spy_open = sinon.spy(indexedDB, "open");
this.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
this.spy_transaction = sinon.spy(IDBDatabase.prototype, "transaction");
this.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
this.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
this.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
this.spy_key_cursor = sinon.spy(IDBIndex.prototype, "openKeyCursor");
},
teardown: function () {
this.spy_open.restore();
delete this.spy_open;
this.spy_create_store.restore();
delete this.spy_create_store;
this.spy_transaction.restore();
delete this.spy_transaction;
this.spy_store.restore();
delete this.spy_store;
this.spy_index.restore();
delete this.spy_index;
this.spy_create_index.restore();
delete this.spy_create_index;
this.spy_key_cursor.restore();
delete this.spy_key_cursor;
}
});
test("spy indexedDB usage", function () {
var context = this;
stop();
expect(30);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.allDocs();
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 3,
"createObjectStore count");
equal(context.spy_create_store.firstCall.args[0], "metadata",
"first createObjectStore first argument");
deepEqual(context.spy_create_store.firstCall.args[1],
{keyPath: "_id", autoIncrement: false},
"first createObjectStore second argument");
equal(context.spy_create_store.secondCall.args[0], "attachment",
"second createObjectStore first argument");
deepEqual(context.spy_create_store.secondCall.args[1],
{keyPath: "_key_path", autoIncrement: false},
"second createObjectStore second argument");
equal(context.spy_create_store.thirdCall.args[0], "blob",
"third createObjectStore first argument");
deepEqual(context.spy_create_store.thirdCall.args[1],
{keyPath: "_key_path", autoIncrement: false},
"third createObjectStore second argument");
equal(context.spy_create_index.callCount, 4, "createIndex count");
equal(context.spy_create_index.firstCall.args[0], "_id",
"first createIndex first argument");
equal(context.spy_create_index.firstCall.args[1], "_id",
"first createIndex second argument");
deepEqual(context.spy_create_index.firstCall.args[2], {unique: true},
"first createIndex third argument");
equal(context.spy_create_index.secondCall.args[0], "_id",
"second createIndex first argument");
equal(context.spy_create_index.secondCall.args[1], "_id",
"second createIndex second argument");
deepEqual(context.spy_create_index.secondCall.args[2], {unique: false},
"second createIndex third argument");
equal(context.spy_create_index.thirdCall.args[0], "_id_attachment",
"third createIndex first argument");
deepEqual(context.spy_create_index.thirdCall.args[1],
["_id", "_attachment"],
"third createIndex second argument");
deepEqual(context.spy_create_index.thirdCall.args[2],
{unique: false},
"third createIndex third argument");
equal(context.spy_create_index.getCall(3).args[0], "_id",
"fourth createIndex first argument");
equal(context.spy_create_index.getCall(3).args[1], "_id",
"fourth createIndex second argument");
deepEqual(context.spy_create_index.getCall(3).args[2], {unique: false},
"fourth createIndex third argument");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0], ["metadata"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readonly",
"transaction second argument");
ok(context.spy_store.calledOnce, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
ok(context.spy_index.calledOnce, "index count " +
context.spy_index.callCount);
deepEqual(context.spy_index.firstCall.args[0], "_id",
"index first argument");
ok(context.spy_key_cursor.calledOnce, "key_cursor count " +
context.spy_key_cursor.callCount);
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("empty result", function () {
var context = this;
stop();
expect(1);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.allDocs();
})
.then(function (result) {
deepEqual(result, {
"data": {
"rows": [
],
"total_rows": 0
}
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("list all documents", function () {
var context = this;
stop();
expect(1);
deleteIndexedDB(context.jio)
.then(function () {
return RSVP.all([
context.jio.put({"_id": "2", "title": "title2"}),
context.jio.put({"_id": "1", "title": "title1"})
]);
})
.then(function () {
return context.jio.allDocs();
})
.then(function (result) {
deepEqual(result, {
"data": {
"rows": [{
"id": "1",
"value": {}
}, {
"id": "2",
"value": {}
}],
"total_rows": 2
}
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.get
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.get", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage", function () {
var context = this;
stop();
expect(15);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_get = sinon.spy(IDBObjectStore.prototype, "get");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
return context.jio.get({"_id": "foo"});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0,
"createObjectStore count");
equal(context.spy_create_index.callCount, 0, "createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["metadata", "attachment"], "transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readonly",
"transaction second argument");
ok(context.spy_store.calledTwice, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "attachment",
"store first argument");
ok(context.spy_get.calledOnce, "index count " +
context.spy_get.callCount);
deepEqual(context.spy_get.firstCall.args[0], "foo",
"get first argument");
ok(context.spy_index.calledOnce, "index count " +
context.spy_index.callCount);
deepEqual(context.spy_index.firstCall.args[0], "_id",
"index first argument");
ok(context.spy_cursor.calledOnce, "cursor count " +
context.spy_cursor.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_get.restore();
delete context.spy_get;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get inexistent document", function () {
var context = this;
stop();
expect(3);
this.jio.get({"_id": "inexistent"})
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.get({"_id": "inexistent"});
})
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Cannot find document");
......@@ -42,861 +382,881 @@
});
});
test("get document", function () {
var id = "post1",
// myAPI,
indexedDB,
mock;
// localStorage[id] = JSON.stringify({
// title: "myPost1"
// });
test("get document without attachment", function () {
var id = "/",
context = this;
stop();
expect(1);
indexedDB = {
open: function () {
var result = {
result: "taboulet"
};
RSVP.delay().then(function () {
result.onsuccess();
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": id, "title": "bar"});
})
.then(function () {
return context.jio.get({"_id": id});
})
.then(function (result) {
deepEqual(result, {
"_id": "/",
"title": "bar"
}, "Check document");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
return result;
}
// return RSVP.success("taboulet");
};
mock = sinon.mock(indexedDB);
// mock = sinon.mock(indexedDB.open, "open", function () {
// var result = {
// result: "taboulet"
// };
// RSVP.delay().then(function () {
// result.onsuccess();
// });
// return result;
// // return RSVP.success("taboulet");
// });
mock.expects("open").once().withArgs("couscous");
test("get document with attachment", function () {
var id = "/",
attachment = "foo",
context = this;
stop();
expect(1);
this.jio.get({"_id": id})
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": id, "title": "bar"});
})
.then(function () {
return context.jio.putAttachment({"_id": id, "_attachment": attachment,
"_data": "bar"});
})
.then(function () {
return context.jio.get({"_id": id});
})
.then(function (result) {
deepEqual(result, {
"title": "myPost1"
"_id": id,
"title": "bar",
"_attachments": {
"foo": {}
}
}, "Check document");
mock.verify();
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
mock.restore();
});
});
}(jIO, QUnit));
// /*jslint indent: 2, maxlen: 80, nomen: true */
// /*global module, test, stop, start, expect, ok, deepEqual, location, sinon,
// davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa, define,
// setTimeout, clearTimeout, indexedDB */
//
// // define([module_name], [dependencies], module);
// (function (dependencies, module) {
// "use strict";
// if (typeof define === 'function' && define.amd) {
// return define(dependencies, module);
// }
// module(test_util, RSVP, jIO);
// }([
// 'test_util',
// 'rsvp',
// 'jio',
// 'indexeddbstorage',
// 'qunit'
// ], function (util, RSVP, jIO) {
// "use strict";
// module("indexeddbStorage");
// function success(promise) {
// return new RSVP.Promise(function (resolve, notify) {
// promise.then(resolve, resolve, notify);
// }, function () {
// promise.cancel();
// });
// }
//
// test("Scenario", 46, function () {
// indexedDB.deleteDatabase("jio:test");
// var server, shared = {}, jio = jIO.createJIO(
// {"type" : "indexeddb",
// "database" : "test"
// },
// {"workspace": {}}
// );
// stop();
// server = {restore: function () {
// return;
// }};
//
// function postNewDocument() {
// 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": 201,
// "statusText": "Created"
// }, "Post a new document");
// ok(util.isUuid(uuid), "New document id should look like " +
// "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + uuid);
// shared.created_document_id = uuid;
// }
//
// function getCreatedDocument() {
// 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() {
// return jio.post({"_id": "b", "title": "Bee"});
// }
//
// function postSpecificDocumentTest(answer) {
// deepEqual(answer, {
// "id": "b",
// "method": "post",
// "result": "success",
// "status": 201,
// "statusText": "Created"
// }, "Post specific document");
// }
//
// function listDocument() {
// 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 listDocumentsWithMetadata() {
// return jio.allDocs({"include_docs": true});
// }
//
// function list2DocumentsWithMetadataTest(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": {},
// "doc": {
// "_id": shared.created_document_id,
// "title": "Unique ID"
// }
// }, {
// "id": "b",
// "value": {},
// "doc": {
// "_id": "b",
// "title": "Bee"
// }
// }]
// },
// "method": "allDocs",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "List 2 documents with their metadata");
// }
//
// function removeCreatedDocument() {
// 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() {
// 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() {
// 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() {
// return jio.put({"_id": "a", "title": "Hey"});
// }
//
// function putNewDocumentTest(answer) {
// deepEqual(answer, {
// "id": "a",
// "method": "put",
// "result": "success",
// "status": 201,
// "statusText": "Created"
// }, "Put new document");
// }
//
// function getCreatedDocument2() {
// 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() {
// return success(jio.post({"_id": "a", "title": "Hoo"}));
// }
//
// function postSameDocumentTest(answer) {
// deepEqual(answer, {
// "error": "conflict",
// "id": "a",
// "message": "Command failed",
// "method": "post",
// "reason": "Document exists",
// "result": "error",
// "status": 409,
// "statusText": "Conflict"
// }, "Unable to post the same document (conflict)");
// }
//
// function putAttachmentToNonExistentDocument() {
// return success(jio.putAttachment({
// "_id": "ahaha",
// "_attachment": "aa",
// "_data": "aaa",
// "_content_type": "text/plain"
// }));
// }
//
// function putAttachmentToNonExistentDocumentTest(answer) {
// deepEqual(answer, {
// "attachment": "aa",
// "error": "not_found",
// "id": "ahaha",
// "message": "indexeddbStorage unable to put attachment",
// "method": "putAttachment",
// "reason": "Not Found",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "Put attachment to a non existent document -> 404 Not Found");
// }
//
// function createAttachment() {
// return jio.putAttachment({
// "_id": "a",
// "_attachment": "aa",
// "_data": "aaa",
// "_content_type": "text/plain"
// });
// }
//
// function createAttachmentTest(answer) {
// deepEqual(answer, {
// "attachment": "aa",
// "id": "a",
// "method": "putAttachment",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Create new attachment");
// }
//
// function updateAttachment() {
// return jio.putAttachment({
// "_id": "a",
// "_attachment": "aa",
// "_data": "aab",
// "_content_type": "text/plain"
// });
// }
//
// function updateAttachmentTest(answer) {
// deepEqual(answer, {
// "attachment": "aa",
// "id": "a",
// "method": "putAttachment",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Update last attachment");
// }
//
// function createAnotherAttachment() {
// return jio.putAttachment({
// "_id": "a",
// "_attachment": "ab",
// "_data": "aba",
// "_content_type": "text/plain"
// });
// }
//
// function createAnotherAttachmentTest(answer) {
// deepEqual(answer, {
// "attachment": "ab",
// "id": "a",
// "method": "putAttachment",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Create another attachment");
// }
//
//
// function updateLastDocument() {
// return jio.put({"_id": "a", "title": "Hoo"});
// }
//
// function updateLastDocumentTest(answer) {
// deepEqual(answer, {
// "id": "a",
// "method": "put",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Update document metadata");
// }
//
// function getFirstAttachment() {
// return jio.getAttachment({"_id": "a", "_attachment": "aa"});
// }
//
// function getFirstAttachmentTest(answer) {
// var blob = answer.data;
// answer.data = "<blob>";
// 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");
// deepEqual(answer, {
// "attachment": "aa",
// "data": "<blob>",
// "id": "a",
// "method": "getAttachment",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get first attachment");
// }, function (err) {
// deepEqual(err, "no error", "Check blob text content");
// });
// }
//
// function getFirstAttachmentRange1() {
// return jio.getAttachment({"_id": "a",
// "_attachment": "aa",
// "_start": 0});
// }
//
// function getFirstAttachmentRangeTest1(answer) {
// var blob = answer.data;
// answer.data = "<blob>";
// 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");
// deepEqual(answer, {
// "attachment": "aa",
// "data": "<blob>",
// "id": "a",
// "method": "getAttachment",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get first attachment with range :_start:0, _end:undefined");
// }, function (err) {
// deepEqual(err, "no error", "Check blob text content");
// });
// }
//
//
// function getFirstAttachmentRange2() {
// return jio.getAttachment({"_id": "a",
// "_attachment": "aa",
// "_start": 0,
// "_end": 1});
// }
//
// function getFirstAttachmentRangeTest2(answer) {
// var blob = answer.data;
// answer.data = "<blob>";
// return jIO.util.readBlobAsText(blob).then(function (e) {
// deepEqual(blob.type, "text/plain", "Check blob type");
// deepEqual(e.target.result, "a", "Check blob text content");
// deepEqual(answer, {
// "attachment": "aa",
// "data": "<blob>",
// "id": "a",
// "method": "getAttachment",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get first attachment with range :_start:0, _end:1");
// }, function (err) {
// deepEqual(err, "no error", "Check blob text content");
// });
// }
//
// function getFirstAttachmentRange3() {
// return jio.getAttachment({"_id": "a",
// "_attachment": "aa",
// "_start": 1,
// "_end": 3});
// }
// function getFirstAttachmentRangeTest3(answer) {
// var blob = answer.data;
// answer.data = "<blob>";
// return jIO.util.readBlobAsText(blob).then(function (e) {
// deepEqual(blob.type, "text/plain", "Check blob type");
// deepEqual(e.target.result, "ab", "Check blob text content");
// deepEqual(answer, {
// "attachment": "aa",
// "data": "<blob>",
// "id": "a",
// "method": "getAttachment",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get first attachment with range :_start:1, _end:3");
// }, function (err) {
// deepEqual(err, "no error", "Check blob text content");
// });
// }
//
//
// function getSecondAttachment() {
// return jio.getAttachment({"_id": "a", "_attachment": "ab"});
// }
//
// function getSecondAttachmentTest(answer) {
// var blob = answer.data;
// answer.data = "<blob>";
// 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");
// deepEqual(answer, {
// "attachment": "ab",
// "data": "<blob>",
// "id": "a",
// "method": "getAttachment",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get second attachment");
// }, function (err) {
// deepEqual(err, "no error", "Check blob text content");
// });
// }
//
//
//
//
//
// function getSecondAttachmentRange1() {
// return success(jio.getAttachment({"_id": "a",
// "_attachment": "ab",
// "_start": -1}));
// }
// function getSecondAttachmentRangeTest1(answer) {
// deepEqual(answer, {
// "attachment": "ab",
// "error": "not_found",
// "id": "a",
// "message": "_start and _end must be positive",
// "method": "getAttachment",
// "reason": "invalide _start, _end",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "get attachment with _start or _end negative -> 404 Not Found");
// }
//
//
//
// function getSecondAttachmentRange2() {
// return success(jio.getAttachment({"_id": "a",
// "_attachment": "ab",
// "_start": 1,
// "_end": 0}));
// }
// function getSecondAttachmentRangeTest2(answer) {
// deepEqual(answer, {
// "attachment": "ab",
// "error": "not_found",
// "id": "a",
// "message": "start is great then end",
// "method": "getAttachment",
// "reason": "invalide offset",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "get attachment with _start > _end -> 404 Not Found");
// }
// function getSecondAttachmentRange3() {
// return jio.getAttachment({"_id": "a",
// "_attachment": "ab",
// "_start": 1,
// "_end": 2});
// }
// function getSecondAttachmentRangeTest3(answer) {
// var blob = answer.data;
// answer.data = "<blob>";
// return jIO.util.readBlobAsText(blob).then(function (e) {
// deepEqual(blob.type, "text/plain", "Check blob type");
// deepEqual(e.target.result, "b", "Check blob text content");
// deepEqual(answer, {
// "attachment": "ab",
// "data": "<blob>",
// "id": "a",
// "method": "getAttachment",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get second attachment with range :_start:1, _end:3");
// }, function (err) {
// deepEqual(err, "no error", "Check blob text content");
// });
// }
//
//
//
// function getLastDocument() {
// return jio.get({"_id": "a"});
// }
//
// function getLastDocumentTest(answer) {
// deepEqual(answer, {
// "data": {
// "_id": "a",
// "title": "Hoo",
// "_attachment": {
// "aa": {
// "content_type": "text/plain",
// "length": 3
// },
// "ab": {
// "content_type": "text/plain",
// "length": 3
// }
// }
// },
// "id": "a",
// "method": "get",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get last document metadata");
// }
//
// function removeSecondAttachment() {
// 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() {
// return success(jio.getAttachment({"_id": "a", "_attachment": "ab"}));
// }
//
// function getInexistentSecondAttachmentTest(answer) {
// deepEqual(answer, {
// "attachment": "ab",
// "error": "not_found",
// "id": "a",
// "message": "IndexeddbStorage, unable to get attachment.",
// "method": "getAttachment",
// "reason": "missing attachment",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "Get inexistent second attachment");
// }
//
// function getOneAttachmentDocument() {
// return jio.get({"_id": "a"});
// }
//
// function getOneAttachmentDocumentTest(answer) {
// deepEqual(answer, {
// "data": {
// "_attachment": {
// "aa": {
// "content_type": "text/plain",
// "length": 3
// }
// },
// "_id": "a",
// "title": "Hoo"
// },
// "id": "a",
// "method": "get",
// "result": "success",
// "status": 200,
// "statusText": "Ok"
// }, "Get document metadata");
// }
//
// function removeSecondAttachmentAgain() {
// return success(jio.removeAttachment({"_id": "a", "_attachment": "ab"}));
// }
//
// function removeSecondAttachmentAgainTest(answer) {
// deepEqual(answer, {
// "attachment": "ab",
// "error": "not_found",
// "id": "a",
// "message": "IndexeddbStorage, document attachment not found.",
// "method": "removeAttachment",
// "reason": "missing attachment",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "Remove inexistent attachment");
// }
//
// function removeDocument() {
// 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() {
// return success(jio.getAttachment({"_id": "a", "_attachment": "aa"}));
// }
//
// function getInexistentFirstAttachmentTest(answer) {
// deepEqual(answer, {
// "attachment": "aa",
// "error": "not_found",
// "id": "a",
// "message": "IndexeddbStorage, unable to get attachment.",
// "method": "getAttachment",
// "reason": "missing attachment",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "Get inexistent first attachment");
// }
//
// function getInexistentDocument() {
// return success(jio.get({"_id": "a"}));
// }
//
// function getInexistentDocumentTest(answer) {
// deepEqual(answer, {
// "error": "not_found",
// "id": "a",
// "message": "IndexeddbStorage, unable to get document.",
// "method": "get",
// "reason": "Not Found",
// "result": "error",
// "status": 404,
// "statusText": "Not Found"
// }, "Get inexistent document");
// }
//
// function removeInexistentDocument() {
// return success(jio.remove({"_id": "a"}));
// }
//
// function removeInexistentDocumentTest(answer) {
// deepEqual(answer, {
// "error": "not_found",
// "id": "a",
// "message": "IndexeddbStorage, unable to get metadata.",
// "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).
// // allD 200 2 documents
// then(listDocument).then(list2DocumentsTest).
// // allD+include_docs 200 2 documents
// then(listDocumentsWithMetadata).then(list2DocumentsWithMetadataTest).
// // 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 404
// then(putAttachmentToNonExistentDocument).
// then(putAttachmentToNonExistentDocumentTest).
// // 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).
// then(getFirstAttachmentRange1).then(getFirstAttachmentRangeTest1).
// then(getFirstAttachmentRange2).then(getFirstAttachmentRangeTest2).
// then(getFirstAttachmentRange3).then(getFirstAttachmentRangeTest3).
// // getA b 200
// then(getSecondAttachment).then(getSecondAttachmentTest).
// then(getSecondAttachmentRange1).then(getSecondAttachmentRangeTest1).
// then(getSecondAttachmentRange2).then(getSecondAttachmentRangeTest2).
// then(getSecondAttachmentRange3).then(getSecondAttachmentRangeTest3).
// // 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).
// // end
// fail(unexpectedError).
// always(start).
// always(function () {
// server.restore();
// });
// });
// }));
});
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.put
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.put", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage", function () {
var context = this;
stop();
expect(31);
deleteIndexedDB(context.jio)
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 3,
"createObjectStore count");
equal(context.spy_create_store.firstCall.args[0], "metadata",
"first createObjectStore first argument");
deepEqual(context.spy_create_store.firstCall.args[1],
{keyPath: "_id", autoIncrement: false},
"first createObjectStore second argument");
equal(context.spy_create_store.secondCall.args[0], "attachment",
"second createObjectStore first argument");
deepEqual(context.spy_create_store.secondCall.args[1],
{keyPath: "_key_path", autoIncrement: false},
"second createObjectStore second argument");
equal(context.spy_create_store.thirdCall.args[0], "blob",
"third createObjectStore first argument");
deepEqual(context.spy_create_store.thirdCall.args[1],
{keyPath: "_key_path", autoIncrement: false},
"third createObjectStore second argument");
equal(context.spy_create_index.callCount, 4, "createIndex count");
equal(context.spy_create_index.firstCall.args[0], "_id",
"first createIndex first argument");
equal(context.spy_create_index.firstCall.args[1], "_id",
"first createIndex second argument");
deepEqual(context.spy_create_index.firstCall.args[2], {unique: true},
"first createIndex third argument");
equal(context.spy_create_index.secondCall.args[0], "_id",
"second createIndex first argument");
equal(context.spy_create_index.secondCall.args[1], "_id",
"second createIndex second argument");
deepEqual(context.spy_create_index.secondCall.args[2],
{unique: false},
"second createIndex third argument");
equal(context.spy_create_index.thirdCall.args[0], "_id_attachment",
"third createIndex first argument");
deepEqual(context.spy_create_index.thirdCall.args[1],
["_id", "_attachment"],
"third createIndex second argument");
deepEqual(context.spy_create_index.thirdCall.args[2], {unique: false},
"third createIndex third argument");
equal(context.spy_create_index.getCall(3).args[0], "_id",
"fourth createIndex first argument");
equal(context.spy_create_index.getCall(3).args[1], "_id",
"fourth createIndex second argument");
deepEqual(context.spy_create_index.getCall(3).args[2], {unique: false},
"fourth createIndex third argument");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0], ["metadata"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readwrite",
"transaction second argument");
ok(context.spy_store.calledOnce, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
ok(context.spy_put.calledOnce, "put count " +
context.spy_put.callCount);
deepEqual(context.spy_put.firstCall.args[0],
{"_id": "foo", title: "bar"},
"put first argument");
ok(!context.spy_index.called, "index count " +
context.spy_index.callCount);
ok(!context.spy_cursor.called, "cursor count " +
context.spy_cursor.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_put.restore();
delete context.spy_put;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("put document", function () {
var context = this;
stop();
expect(1);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "inexistent"});
})
.then(function (result) {
equal(result, "inexistent");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.remove
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.remove", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage with one document", function () {
var context = this;
stop();
expect(18);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
return context.jio.remove({"_id": "foo"});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0,
"createObjectStore count");
equal(context.spy_create_index.callCount, 0, "createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["metadata", "attachment", "blob"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readwrite",
"transaction second argument");
equal(context.spy_store.callCount, 3, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "attachment",
"store first argument");
deepEqual(context.spy_store.thirdCall.args[0], "blob",
"store first argument");
ok(context.spy_delete.calledOnce, "delete count " +
context.spy_delete.callCount);
deepEqual(context.spy_delete.firstCall.args[0], "foo",
"delete first argument");
ok(context.spy_index.calledTwice, "index count " +
context.spy_index.callCount);
deepEqual(context.spy_index.firstCall.args[0], "_id",
"index first argument");
deepEqual(context.spy_index.secondCall.args[0], "_id",
"index first argument");
ok(context.spy_cursor.calledTwice, "cursor count " +
context.spy_cursor.callCount);
equal(context.spy_cursor_delete.callCount, 0, "cursor count " +
context.spy_cursor_delete.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_delete.restore();
delete context.spy_delete;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
context.spy_cursor_delete.restore();
delete context.spy_cursor_delete;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("spy indexedDB usage with 2 attachments", function () {
var context = this;
stop();
expect(18);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
return RSVP.all([
context.jio.putAttachment({"_id": "foo",
"_attachment": "attachment1",
"_data": "bar"}),
context.jio.putAttachment({"_id": "foo",
"_attachment": "attachment2",
"_data": "bar2"})
]);
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
return context.jio.remove({"_id": "foo"});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0, "createObjectStore count");
equal(context.spy_create_index.callCount, 0, "createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["metadata", "attachment", "blob"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readwrite",
"transaction second argument");
equal(context.spy_store.callCount, 3, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "attachment",
"store first argument");
deepEqual(context.spy_store.thirdCall.args[0], "blob",
"store first argument");
equal(context.spy_delete.callCount, 1, "delete count " +
context.spy_delete.callCount);
deepEqual(context.spy_delete.firstCall.args[0], "foo",
"delete first argument");
ok(context.spy_index.calledTwice, "index count " +
context.spy_index.callCount);
deepEqual(context.spy_index.firstCall.args[0], "_id",
"index first argument");
deepEqual(context.spy_index.secondCall.args[0], "_id",
"index first argument");
ok(context.spy_cursor.calledTwice, "cursor count " +
context.spy_cursor.callCount);
equal(context.spy_cursor_delete.callCount, 3, "cursor count " +
context.spy_cursor_delete.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_delete.restore();
delete context.spy_delete;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
context.spy_cursor_delete.restore();
delete context.spy_cursor_delete;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.getAttachment
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.getAttachment", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage", function () {
var context = this,
attachment = "attachment";
stop();
expect(15);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
return context.jio.putAttachment({"_id": "foo",
"_attachment": attachment,
"_data": big_string});
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_get = sinon.spy(IDBObjectStore.prototype, "get");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
return context.jio.getAttachment({"_id": "foo",
"_attachment": attachment});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0,
"createObjectStore count");
equal(context.spy_create_index.callCount, 0, "createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["attachment", "blob"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readonly",
"transaction second argument");
equal(context.spy_store.callCount, 2, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "attachment",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "blob",
"store first argument");
equal(context.spy_get.callCount, 3, "get count " +
context.spy_get.callCount);
deepEqual(context.spy_get.firstCall.args[0], "foo_attachment",
"get first argument");
deepEqual(context.spy_get.secondCall.args[0], "foo_attachment_0",
"get first argument");
deepEqual(context.spy_get.thirdCall.args[0], "foo_attachment_1",
"get first argument");
ok(!context.spy_index.called, "index count " +
context.spy_index.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_get.restore();
delete context.spy_get;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("check result", function () {
var context = this,
attachment = "attachment";
stop();
expect(2);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
return context.jio.putAttachment({"_id": "foo",
"_attachment": attachment,
"_data": big_string});
})
.then(function () {
return context.jio.getAttachment({"_id": "foo",
"_attachment": attachment});
})
.then(function (result) {
ok(result.data instanceof Blob, "Data is Blob");
return jIO.util.readBlobAsText(result.data);
})
.then(function (result) {
equal(result.target.result, big_string,
"Attachment correctly fetched");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("streaming", function () {
var context = this,
attachment = "attachment";
stop();
expect(2);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
return context.jio.putAttachment({"_id": "foo",
"_attachment": attachment,
"_data": big_string});
})
.then(function () {
return context.jio.getAttachment({"_id": "foo",
"_attachment": attachment,
"_start": 1999995, "_end": 2000005});
})
.then(function (result) {
ok(result.data instanceof Blob, "Data is Blob");
return jIO.util.readBlobAsText(result.data);
})
.then(function (result) {
var expected = "aaaaaaaaaa";
equal(result.target.result, expected, "Attachment correctly fetched");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.removeAttachment
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.removeAttachment", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage", function () {
var context = this,
attachment = "attachment";
stop();
expect(15);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
return context.jio.putAttachment({"_id": "foo",
"_attachment": attachment,
"_data": big_string});
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype,
"objectStore");
context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
return context.jio.removeAttachment({"_id": "foo",
"_attachment": attachment});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0,
"createObjectStore count");
equal(context.spy_create_index.callCount, 0,
"createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["attachment", "blob"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readwrite",
"transaction second argument");
equal(context.spy_store.callCount, 2, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "attachment",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "blob",
"store first argument");
equal(context.spy_delete.callCount, 1, "delete count " +
context.spy_delete.callCount);
deepEqual(context.spy_delete.firstCall.args[0], "foo_attachment",
"delete first argument");
ok(context.spy_index.calledOnce, "index count " +
context.spy_index.callCount);
ok(context.spy_cursor.calledOnce, "cursor count " +
context.spy_cursor.callCount);
equal(context.spy_cursor_delete.callCount, 2, "cursor count " +
context.spy_cursor_delete.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_delete.restore();
delete context.spy_delete;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
context.spy_cursor_delete.restore();
delete context.spy_cursor_delete;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.putAttachment
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.putAttachment", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage", function () {
var context = this,
attachment = "attachment";
stop();
expect(21);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
return context.jio.putAttachment({"_id": "foo",
"_attachment": attachment,
"_data": big_string});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0,
"createObjectStore count");
equal(context.spy_create_index.callCount, 0,
"createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["attachment", "blob"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readwrite",
"transaction second argument");
equal(context.spy_store.callCount, 4, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "attachment",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "blob",
"store first argument");
deepEqual(context.spy_store.thirdCall.args[0], "attachment",
"store first argument");
deepEqual(context.spy_store.getCall(3).args[0], "blob",
"store first argument");
equal(context.spy_delete.callCount, 1, "delete count " +
context.spy_delete.callCount);
deepEqual(context.spy_delete.firstCall.args[0], "foo_attachment",
"delete first argument");
ok(context.spy_index.calledOnce, "index count " +
context.spy_index.callCount);
ok(context.spy_cursor.calledOnce, "cursor count " +
context.spy_cursor.callCount);
equal(context.spy_cursor_delete.callCount, 0, "delete count " +
context.spy_cursor_delete.callCount);
equal(context.spy_put.callCount, 3, "put count " +
context.spy_put.callCount);
deepEqual(context.spy_put.firstCall.args[0], {
"_attachment": "attachment",
"_id": "foo",
"_key_path": "foo_attachment",
"info": {
"content_type": "",
"length": 3000000
}
}, "put first argument");
delete context.spy_put.secondCall.args[0].blob;
// XXX Check blob content
deepEqual(context.spy_put.secondCall.args[0], {
"_attachment": "attachment",
"_id": "foo",
"_part": 0,
"_key_path": "foo_attachment_0"
}, "put first argument");
delete context.spy_put.thirdCall.args[0].blob;
// XXX Check blob content
deepEqual(context.spy_put.thirdCall.args[0], {
"_attachment": "attachment",
"_id": "foo",
"_part": 1,
"_key_path": "foo_attachment_1"
}, "put first argument");
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_delete.restore();
delete context.spy_delete;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
context.spy_cursor_delete.restore();
delete context.spy_cursor_delete;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
}(jIO, QUnit, indexedDB, Blob, sinon, IDBDatabase,
IDBTransaction, IDBIndex, IDBObjectStore, IDBCursor));
......@@ -10,6 +10,9 @@
<script src="../node_modules/grunt-contrib-qunit/test/libs/qunit.js" type="text/javascript"></script>
<script src="../node_modules/sinon/pkg/sinon.js" type="text/javascript"></script>
<script>
QUnit.config.testTimeout = 5000;
</script>
<!--script src="html5.js"></script-->
<!--script src="jio/util.js"></script-->
<!--script src="jio/fakestorage.js"></script>
......@@ -33,8 +36,8 @@
<script src="jio.storage/drivetojiomapping.tests.js"></script>
<script src="jio.storage/unionstorage.tests.js"></script>
<script src="jio.storage/erp5storage.tests.js"></script>
<script src="jio.storage/indexeddbstorage.tests.js"></script>
<!--script src="jio.storage/indexeddbstorage.tests.js"></script-->
<!--script src="jio.storage/indexstorage.tests.js"></script-->
<!--script src="jio.storage/dropboxstorage.tests.js"></script-->
......
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