Commit 6ef1d4b4 authored by Tristan Cavelier's avatar Tristan Cavelier

Improve JIO and OfficeJS.

Jio jobs now knows what to do if eliminated, updated or not accepted.
We can make DummyStorageAll3tries be different from other similar storage by
adding some useless parameters. So older similar storages won't be replaced.
Correcting some bugs in replicatestorage.
Adding one qunit test (jio does not pass it...)
In intro.js, `var log' is used for debuging.
Better applications managing in OfficeJS.
parent 5e2582e0
......@@ -212,7 +212,9 @@
documentList:[],
gadget_object:{}, // contains current gadgets id with their location
currentFile:null,
currentEditor:null
currentEditor:null,
currentApp:null,
currentActivity:null
};
priv.loading_object = {
spinstate: 0,
......@@ -324,6 +326,7 @@
priv.data_object.currentEditor = null;
break;
}
priv.data_object.currentApp = realapp;
}
// onload call
if (typeof realapp.onload !== 'undefined') {
......@@ -442,7 +445,7 @@
console.error (result.error.message);
}
priv.loading_object.end_getlist();
if (typeof callback !== 'undefined') {
if (typeof callback === 'function') {
callback();
}
}
......@@ -551,7 +554,13 @@
cpt += 1;
if (cpt === l) {
if (typeof current_editor.update !== 'undefined') {
that.getList(current_editor.update);
if (priv.data_object.currentEditor !== null &&
current_editor.path ===
priv.data_object.currentEditor.path) {
that.getList(current_editor.update);
} else {
that.getList();
}
}
}
priv.loading_object.end_remove();
......@@ -566,16 +575,20 @@
for (i = 0; i < activity.length; i+= 1) {
switch (activity[i].command.label) {
case 'saveDocument':
res.push('Saving "' + activity[i].command.path + '",');
res.push(activity[i].storage.type+
': Saving "' + activity[i].command.path + '".');
break;
case 'loadDocument':
res.push('Loading "' + activity[i].command.path + '".');
res.push(activity[i].storage.type+
': Loading "' + activity[i].command.path + '".');
break;
case 'removeDocument':
res.push('Removing "' + activity[i].command.path + '".');
res.push(activity[i].storage.type+
': Removing "' + activity[i].command.path + '".');
break;
case 'getDocumentList':
res.push('Get document list' +
res.push(activity[i].storage.type+
': Get document list' +
' at "' + activity[i].command.path + '".');
break;
default:
......@@ -599,7 +612,7 @@
break;
case 'getDocumentList':
res.push('<span style="color:red;">LastFailure: '+
'Fail to retreive list from ' +
'Fail to retreive list ' +
' at "' + lastfailure.path + '"</span>');
break;
default:
......
/*! JIO - v0.1.0 - 2012-06-15
/*! JIO - v0.1.0 - 2012-06-18
* Copyright (c) 2012 Nexedi; Licensed */
var jio = (function () {
var log = function(){};
// var log = console.log;
var jioException = function(spec, my) {
var that = {};
......@@ -75,6 +77,7 @@ var storage = function(spec, my) {
// Attributes //
var priv = {};
priv.type = spec.type || '';
log ('new storage spec: ' + JSON.stringify (spec));
// Methods //
that.getType = function() {
......@@ -90,9 +93,12 @@ var storage = function(spec, my) {
* @param {object} command The command
*/
that.execute = function(command) {
log ('storage '+that.getType()+' execute(command): ' +
JSON.stringify (command.serialized()));
that.validate(command);
that.done = command.done;
that.fail = command.fail;
that.end = command.end;
command.executeOn(that);
};
......@@ -135,12 +141,18 @@ var storage = function(spec, my) {
that.saveDocument();
};
/**
* Validate the storage state. It returns a empty string all is ok.
* @method validateState
* @return {string} empty: ok, else error message.
*/
that.validateState = function() {
return '';
};
that.done = function() {};
that.fail = function() {};
that.end = function() {}; // terminate the current job.
return that;
};
......@@ -149,6 +161,7 @@ var storageHandler = function(spec, my) {
spec = spec || {};
my = my || {};
var that = storage( spec, my );
log ('new storageHandler spec: '+JSON.stringify (spec));
that.newCommand = function (method, spec) {
var o = spec || {};
......@@ -162,6 +175,10 @@ var storageHandler = function(spec, my) {
};
that.addJob = function (storage,command) {
log ('storageHandler ' + that.getType() +
' addJob (storage, command): ' +
JSON.stringify (storage.serialized()) + ', ' +
JSON.stringify (command.serialized()));
my.jobManager.addJob ( job({storage:storage, command:command}, my) );
};
......@@ -273,21 +290,27 @@ var command = function(spec, my) {
};
that.done = function(return_value) {
log ('command done: ' + JSON.stringify (return_value));
priv.respond({status:doneStatus(),value:return_value});
priv.done(return_value);
priv.end();
priv.end(doneStatus());
};
that.fail = function(return_error) {
log ('command fail: ' + JSON.stringify (return_error));
if (priv.option.max_retry === 0 || priv.tried < priv.option.max_retry) {
priv.retry();
} else {
priv.respond({status:failStatus(),error:return_error});
priv.fail(return_error);
priv.end();
priv.end(failStatus());
}
};
that.end = function () {
priv.end(doneStatus());
};
that.onResponseDo = function (fun) {
if (fun) {
priv.respond = fun;
......@@ -358,10 +381,12 @@ var command = function(spec, my) {
* @return {object} The clone of the command options.
*/
that.cloneOption = function () {
// log ('command cloneOption(): ' + JSON.stringify (priv.option));
var k, o = {};
for (k in priv.option) {
o[k] = priv.option[k];
}
// log ('cloneOption result: ' + JSON.stringify (o));
return o;
};
......@@ -722,16 +747,16 @@ var job = function(spec, my) {
priv.storage = spec.storage;
priv.status = initialStatus();
priv.date = new Date();
log ('new job spec: ' + JSON.stringify (spec) + ', priv: ' +
JSON.stringify (priv));
// Initialize //
(function() {
if (!priv.storage){
throw invalidJobException({job:that,message:'No storage set'});
}
if (!priv.command){
throw invalidJobException({job:that,message:'No command set'});
}
}());
if (!priv.storage){
throw invalidJobException({job:that,message:'No storage set'});
}
if (!priv.command){
throw invalidJobException({job:that,message:'No command set'});
}
// Methods //
/**
* Returns the job command.
......@@ -790,6 +815,7 @@ var job = function(spec, my) {
* @param {object} job The job to wait for.
*/
that.waitForJob = function(job) {
log ('job waitForJob(job): ' + JSON.stringify (job.serialized()));
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus({},my);
}
......@@ -813,6 +839,7 @@ var job = function(spec, my) {
* @param {number} ms Time to wait in millisecond.
*/
that.waitForTime = function(ms) {
log ('job waitForTime(ms): ' + ms);
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus({},my);
}
......@@ -829,13 +856,35 @@ var job = function(spec, my) {
}
};
that.eliminated = function () {
priv.command.setMaxRetry(-1);
log ('job eliminated(): '+JSON.stringify (that.serialized()));
priv.command.fail({status:0,statusText:'Stoped',
message:'This job has been stoped by another one.'});
};
that.notAccepted = function () {
log ('job notAccepted(): '+JSON.stringify (that.serialized()));
priv.command.setMaxRetry(-1);
priv.command.onEndDo (function () {
priv.status = failStatus();
my.jobManager.terminateJob (that);
});
priv.command.fail ({status:0,statusText:'Not Accepted',
message:'This job is already running.'});
};
/**
* Updates the date of the job with the another one.
* @method update
* @param {object} job The other job.
*/
that.update = function(job) {
log ('job update(job): ' + JSON.stringify (job.serialized()));
priv.command.setMaxRetry(-1);
priv.command.onEndDo(function (status) {
console.log ('job update on end' + status.getLabel());
});
priv.command.fail({status:0,statusText:'Replaced',
message:'Job has been replaced by another one.'});
priv.date = job.getDate();
......@@ -844,6 +893,7 @@ var job = function(spec, my) {
};
that.execute = function() {
log ('job execute(): ' + JSON.stringify (that.serialized()));
if (priv.max_retry !== 0 && priv.tried >= priv.max_retry) {
throw tooMuchTriesJobException(
{job:that,message:'The job was invoked too much time.'});
......@@ -853,6 +903,7 @@ var job = function(spec, my) {
}
priv.status = onGoingStatus();
priv.command.onRetryDo (function() {
log ('command.retry job:' + JSON.stringify (that.serialized()));
var ms = priv.command.getTried();
ms = ms*ms*200;
if (ms>10000){
......@@ -860,7 +911,9 @@ var job = function(spec, my) {
}
that.waitForTime(ms);
});
priv.command.onEndDo (function() {
priv.command.onEndDo (function(status) {
priv.status = status;
log ('command.end job:' + JSON.stringify (that.serialized()));
my.jobManager.terminateJob (that);
});
priv.command.execute (priv.storage);
......@@ -1181,11 +1234,11 @@ var jobManager = (function(spec, my) {
var i, jio_job_array;
jio_job_array = LocalOrCookieStorage.getItem('jio/job_array/'+id)||[];
for (i = 0; i < jio_job_array.length; i+= 1) {
var command_o = command(jio_job_array[i].command, my);
if (command_o.canBeRestored()) {
var command_object = command(jio_job_array[i].command, my);
if (command_object.canBeRestored()) {
that.addJob ( job(
{storage:jioNamespace.storage(jio_job_array[i].storage,my),
command:command_o}, my));
command:command_object}, my));
}
}
};
......@@ -1300,12 +1353,13 @@ var jobManager = (function(spec, my) {
}
for (i = 0; i < result_a.length; i+= 1) {
if (result_a[i].action === 'dont accept') {
return;
return job.notAccepted();
}
}
for (i = 0; i < result_a.length; i+= 1) {
switch (result_a[i].action) {
case 'eliminate':
result_a[i].job.eliminated();
priv.removeJob(result_a[i].job);
break;
case 'update':
......@@ -1347,6 +1401,14 @@ var jobRules = (function(spec, my) {
that.none = function() { return 'none'; };
that.default_action = that.none;
that.default_compare = function(job1,job2) {
if (job1.getCommand().getPath() === job2.getCommand().getPath() &&
JSON.stringify(job1.getStorage().serialized()) ===
JSON.stringify(job2.getStorage().serialized())) {
console.log ('same ! ' + job1.getCommand().getPath() + ', ' +
job2.getCommand().getPath() + ', ' +
JSON.stringify (job1.getStorage().serialized())+', '+
JSON.stringify (job2.getStorage().serialized()));
}
return (job1.getCommand().getPath() === job2.getCommand().getPath() &&
JSON.stringify(job1.getStorage().serialized()) ===
JSON.stringify(job2.getStorage().serialized()));
......
This diff is collapsed.
/*! JIO Storage - v0.1.0 - 2012-06-15
/*! JIO Storage - v0.1.0 - 2012-06-18
* Copyright (c) 2012 Nexedi; Licensed */
(function(LocalOrCookieStorage, $, Base64, sjcl, Jio) {
......@@ -506,7 +506,6 @@ var newReplicateStorage = function ( spec, my ) {
that.done (result);
}
};
command.setMaxRetry (1);
for (i = 0; i < priv.nb_storage; i+= 1) {
var newcommand = command.clone();
var newstorage = that.newStorage(priv.storagelist[i]);
......@@ -515,6 +514,7 @@ var newReplicateStorage = function ( spec, my ) {
newcommand.onDoneDo (onDoneDo);
that.addJob (newstorage, newcommand);
}
command.setMaxRetry (1);
};
/**
......@@ -523,8 +523,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.saveDocument = function (command) {
priv.doJob (
command.clone(),
command,
'All save "'+ command.getPath() +'" requests have failed.');
that.end();
};
/**
......@@ -534,8 +535,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.loadDocument = function (command) {
priv.doJob (
command.clone(),
command,
'All load "'+ command.getPath() +'" requests have failed.');
that.end();
};
/**
......@@ -545,8 +547,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.getDocumentList = function (command) {
priv.doJob (
command.clone(),
command,
'All get document list requests have failed.');
that.end();
};
/**
......@@ -555,8 +558,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.removeDocument = function (command) {
priv.doJob (
command.clone(),
command,
'All remove "' + command.getPath() + '" requests have failed.');
that.end();
};
return that;
......
This diff is collapsed.
......@@ -169,6 +169,17 @@
that.setType('dummyall3tries');
// this serialized method is used to make simple difference between
// two dummyall3tries storages:
// so {type:'dummyall3tries',a:'b'} differs from
// {type:'dummyall3tries',c:'d'}.
var super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.spec = spec;
return o;
};
priv.doJob = function (command,if_ok_return) {
// wait a little in order to simulate asynchronous operation
setTimeout(function () {
......
......@@ -47,7 +47,6 @@ var newReplicateStorage = function ( spec, my ) {
that.done (result);
}
};
command.setMaxRetry (1);
for (i = 0; i < priv.nb_storage; i+= 1) {
var newcommand = command.clone();
var newstorage = that.newStorage(priv.storagelist[i]);
......@@ -56,6 +55,7 @@ var newReplicateStorage = function ( spec, my ) {
newcommand.onDoneDo (onDoneDo);
that.addJob (newstorage, newcommand);
}
command.setMaxRetry (1);
};
/**
......@@ -64,8 +64,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.saveDocument = function (command) {
priv.doJob (
command.clone(),
command,
'All save "'+ command.getPath() +'" requests have failed.');
that.end();
};
/**
......@@ -75,8 +76,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.loadDocument = function (command) {
priv.doJob (
command.clone(),
command,
'All load "'+ command.getPath() +'" requests have failed.');
that.end();
};
/**
......@@ -86,8 +88,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.getDocumentList = function (command) {
priv.doJob (
command.clone(),
command,
'All get document list requests have failed.');
that.end();
};
/**
......@@ -96,8 +99,9 @@ var newReplicateStorage = function ( spec, my ) {
*/
that.removeDocument = function (command) {
priv.doJob (
command.clone(),
command,
'All remove "' + command.getPath() + '" requests have failed.');
that.end();
};
return that;
......
......@@ -103,21 +103,27 @@ var command = function(spec, my) {
};
that.done = function(return_value) {
log ('command done: ' + JSON.stringify (return_value));
priv.respond({status:doneStatus(),value:return_value});
priv.done(return_value);
priv.end();
priv.end(doneStatus());
};
that.fail = function(return_error) {
log ('command fail: ' + JSON.stringify (return_error));
if (priv.option.max_retry === 0 || priv.tried < priv.option.max_retry) {
priv.retry();
} else {
priv.respond({status:failStatus(),error:return_error});
priv.fail(return_error);
priv.end();
priv.end(failStatus());
}
};
that.end = function () {
priv.end(doneStatus());
};
that.onResponseDo = function (fun) {
if (fun) {
priv.respond = fun;
......@@ -188,10 +194,12 @@ var command = function(spec, my) {
* @return {object} The clone of the command options.
*/
that.cloneOption = function () {
// log ('command cloneOption(): ' + JSON.stringify (priv.option));
var k, o = {};
for (k in priv.option) {
o[k] = priv.option[k];
}
// log ('cloneOption result: ' + JSON.stringify (o));
return o;
};
......
var jio = (function () {
var log = function(){};
// var log = console.log;
......@@ -9,16 +9,16 @@ var job = function(spec, my) {
priv.storage = spec.storage;
priv.status = initialStatus();
priv.date = new Date();
log ('new job spec: ' + JSON.stringify (spec) + ', priv: ' +
JSON.stringify (priv));
// Initialize //
(function() {
if (!priv.storage){
throw invalidJobException({job:that,message:'No storage set'});
}
if (!priv.command){
throw invalidJobException({job:that,message:'No command set'});
}
}());
if (!priv.storage){
throw invalidJobException({job:that,message:'No storage set'});
}
if (!priv.command){
throw invalidJobException({job:that,message:'No command set'});
}
// Methods //
/**
* Returns the job command.
......@@ -77,6 +77,7 @@ var job = function(spec, my) {
* @param {object} job The job to wait for.
*/
that.waitForJob = function(job) {
log ('job waitForJob(job): ' + JSON.stringify (job.serialized()));
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus({},my);
}
......@@ -100,6 +101,7 @@ var job = function(spec, my) {
* @param {number} ms Time to wait in millisecond.
*/
that.waitForTime = function(ms) {
log ('job waitForTime(ms): ' + ms);
if (priv.status.getLabel() !== 'wait') {
priv.status = waitStatus({},my);
}
......@@ -116,13 +118,35 @@ var job = function(spec, my) {
}
};
that.eliminated = function () {
priv.command.setMaxRetry(-1);
log ('job eliminated(): '+JSON.stringify (that.serialized()));
priv.command.fail({status:0,statusText:'Stoped',
message:'This job has been stoped by another one.'});
};
that.notAccepted = function () {
log ('job notAccepted(): '+JSON.stringify (that.serialized()));
priv.command.setMaxRetry(-1);
priv.command.onEndDo (function () {
priv.status = failStatus();
my.jobManager.terminateJob (that);
});
priv.command.fail ({status:0,statusText:'Not Accepted',
message:'This job is already running.'});
};
/**
* Updates the date of the job with the another one.
* @method update
* @param {object} job The other job.
*/
that.update = function(job) {
log ('job update(job): ' + JSON.stringify (job.serialized()));
priv.command.setMaxRetry(-1);
priv.command.onEndDo(function (status) {
console.log ('job update on end' + status.getLabel());
});
priv.command.fail({status:0,statusText:'Replaced',
message:'Job has been replaced by another one.'});
priv.date = job.getDate();
......@@ -131,6 +155,7 @@ var job = function(spec, my) {
};
that.execute = function() {
log ('job execute(): ' + JSON.stringify (that.serialized()));
if (priv.max_retry !== 0 && priv.tried >= priv.max_retry) {
throw tooMuchTriesJobException(
{job:that,message:'The job was invoked too much time.'});
......@@ -140,6 +165,7 @@ var job = function(spec, my) {
}
priv.status = onGoingStatus();
priv.command.onRetryDo (function() {
log ('command.retry job:' + JSON.stringify (that.serialized()));
var ms = priv.command.getTried();
ms = ms*ms*200;
if (ms>10000){
......@@ -147,7 +173,9 @@ var job = function(spec, my) {
}
that.waitForTime(ms);
});
priv.command.onEndDo (function() {
priv.command.onEndDo (function(status) {
priv.status = status;
log ('command.end job:' + JSON.stringify (that.serialized()));
my.jobManager.terminateJob (that);
});
priv.command.execute (priv.storage);
......
......@@ -140,11 +140,11 @@ var jobManager = (function(spec, my) {
var i, jio_job_array;
jio_job_array = LocalOrCookieStorage.getItem('jio/job_array/'+id)||[];
for (i = 0; i < jio_job_array.length; i+= 1) {
var command_o = command(jio_job_array[i].command, my);
if (command_o.canBeRestored()) {
var command_object = command(jio_job_array[i].command, my);
if (command_object.canBeRestored()) {
that.addJob ( job(
{storage:jioNamespace.storage(jio_job_array[i].storage,my),
command:command_o}, my));
command:command_object}, my));
}
}
};
......@@ -259,12 +259,13 @@ var jobManager = (function(spec, my) {
}
for (i = 0; i < result_a.length; i+= 1) {
if (result_a[i].action === 'dont accept') {
return;
return job.notAccepted();
}
}
for (i = 0; i < result_a.length; i+= 1) {
switch (result_a[i].action) {
case 'eliminate':
result_a[i].job.eliminated();
priv.removeJob(result_a[i].job);
break;
case 'update':
......
......@@ -12,6 +12,14 @@ var jobRules = (function(spec, my) {
that.none = function() { return 'none'; };
that.default_action = that.none;
that.default_compare = function(job1,job2) {
if (job1.getCommand().getPath() === job2.getCommand().getPath() &&
JSON.stringify(job1.getStorage().serialized()) ===
JSON.stringify(job2.getStorage().serialized())) {
console.log ('same ! ' + job1.getCommand().getPath() + ', ' +
job2.getCommand().getPath() + ', ' +
JSON.stringify (job1.getStorage().serialized())+', '+
JSON.stringify (job2.getStorage().serialized()));
}
return (job1.getCommand().getPath() === job2.getCommand().getPath() &&
JSON.stringify(job1.getStorage().serialized()) ===
JSON.stringify(job2.getStorage().serialized()));
......
......@@ -5,6 +5,7 @@ var storage = function(spec, my) {
// Attributes //
var priv = {};
priv.type = spec.type || '';
log ('new storage spec: ' + JSON.stringify (spec));
// Methods //
that.getType = function() {
......@@ -20,9 +21,12 @@ var storage = function(spec, my) {
* @param {object} command The command
*/
that.execute = function(command) {
log ('storage '+that.getType()+' execute(command): ' +
JSON.stringify (command.serialized()));
that.validate(command);
that.done = command.done;
that.fail = command.fail;
that.end = command.end;
command.executeOn(that);
};
......@@ -65,12 +69,18 @@ var storage = function(spec, my) {
that.saveDocument();
};
/**
* Validate the storage state. It returns a empty string all is ok.
* @method validateState
* @return {string} empty: ok, else error message.
*/
that.validateState = function() {
return '';
};
that.done = function() {};
that.fail = function() {};
that.end = function() {}; // terminate the current job.
return that;
};
......@@ -2,6 +2,7 @@ var storageHandler = function(spec, my) {
spec = spec || {};
my = my || {};
var that = storage( spec, my );
log ('new storageHandler spec: '+JSON.stringify (spec));
that.newCommand = function (method, spec) {
var o = spec || {};
......@@ -15,6 +16,10 @@ var storageHandler = function(spec, my) {
};
that.addJob = function (storage,command) {
log ('storageHandler ' + that.getType() +
' addJob (storage, command): ' +
JSON.stringify (storage.serialized()) + ', ' +
JSON.stringify (command.serialized()));
my.jobManager.addJob ( job({storage:storage, command:command}, my) );
};
......
......@@ -746,7 +746,7 @@ test ('Get Document List', function () {
o.mytest = function (message,value) {
o.f = function (result) {
deepEqual (objectifyDocumentArray(result.value),
objectifyDocumentArray(value),'getting list');
objectifyDocumentArray(value),message);
};
o.t.spy(o,'f');
o.jio.getDocumentList('.',{onResponse:o.f,max_retry:3});
......@@ -762,7 +762,15 @@ test ('Get Document List', function () {
last_modified:15000,creation_date:10000};
o.doc2 = {name:'memo',
last_modified:25000,creation_date:20000};
o.mytest('DummyStorageAllOK,3tries: get document list .',[o.doc1,o.doc2]);
o.mytest('DummyStorageAllOK,3tries: get document list.',
[o.doc1,o.doc2]);
o.jio.stop();
o.jio = JIO.newJio({type:'replicate',storagelist:[
{type:'dummyall3tries',username:'3'},
{type:'dummyall3tries',username:'4'}]});
o.mytest('DummyStorageAll3tries,3tries: get document list.',
[o.doc1,o.doc2]);
o.jio.stop();
});
......@@ -776,7 +784,7 @@ test ('Remove document', function () {
};
o.t.spy(o,'f');
o.jio.removeDocument('file',{onResponse:o.f,max_retry:3});
o.clock.tick(100000);
o.clock.tick(10000);
if (!o.f.calledOnce) {
ok(false, 'no response / too much results');
}
......@@ -786,6 +794,31 @@ test ('Remove document', function () {
{type:'dummyall3tries',username:'2'}]});
o.mytest('DummyStorageAllOK,3tries: remove document.','done');
o.jio.stop();
o.jio = JIO.newJio({type:'replicate',storagelist:[
{type:'dummyall3tries',username:'a'},
{type:'dummyall3tries',username:'b'}]});
o.f = function (result) {
if (!result.status.isDone()) {
ok (false, 'Remove failed!');
}
};
o.f2 = function (result) {
if (!result.status.isDone()) {
ok (false, 'Remove failed!');
}
};
o.t.spy(o,'f');
o.t.spy(o,'f2');
o.jio.removeDocument('file',{onResponse:o.f,max_retry:3});
o.jio.removeDocument('memo',{onResponse:o.f2,max_retry:3});
o.clock.tick(5000);
ok (o.f.calledOnce && o.f2.calledOnce,
'DummyStorageAll3tries,3tries: remove document 2 times at once');
if (!(o.f.calledOnce && o.f2.calledOnce)) {
ok (o.f.calledOnce, 'first callback called once');
ok (o.f2.calledOnce, 'second callback called once');
}
});
module ('Jio IndexedStorage');
......
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