diff --git a/src/jio.storage/indexstorage.js b/src/jio.storage/indexstorage.js
index 07a51feb9a0e4130436c2c496d13ac746e12a40b..cb77d0e17a555a786a4ce34f1fbe3fce7ec14492 100644
--- a/src/jio.storage/indexstorage.js
+++ b/src/jio.storage/indexstorage.js
@@ -17,7 +17,7 @@
  */
 
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
-/*global jIO, define, complex_queries */
+/*global window, exports, require, define, jIO, RSVP, complex_queries */
 
 /**
  * JIO Index Storage.
@@ -118,131 +118,23 @@
   if (typeof define === 'function' && define.amd) {
     return define(dependencies, module);
   }
-  module(jIO, complex_queries);
-}(['jio', 'complex_queries'], function (jIO, complex_queries) {
-  "use strict";
-
-  var error_dict = {
-    "Corrupted Index": {
-      "status": 24,
-      "statusText": "Corrupt",
-      "error": "corrupt",
-      "reason": "corrupted index database"
-    },
-    "Corrupted Metadata": {
-      "status": 24,
-      "statusText": "Corrupt",
-      "error": "corrupt",
-      "reason": "corrupted document"
-    },
-    "Not Found": {
-      "status": 404,
-      "statusText": "Not Found",
-      "error": "not_found",
-      "reason": "missing document"
-    },
-    "Conflict": {
-      "status": 409,
-      "statusText": "Conflicts",
-      "error": "conflicts",
-      "reason": "already exist"
-    },
-    "Different Index": {
-      "status": 40,
-      "statusText": "Check failed",
-      "error": "check_failed",
-      "reason": "incomplete database"
-    }
-  };
-
-  /**
-   * Generate a JIO Error Object
-   *
-   * @method generateErrorObject
-   * @param  {String} name The error name
-   * @param  {String} message The error message
-   * @param  {String} [reason] The error reason
-   * @return {Object} A jIO error object
-   */
-  function generateErrorObject(name, message, reason) {
-    if (!error_dict[name]) {
-      return {
-        "status": 0,
-        "statusText": "Unknown",
-        "error": "unknown",
-        "message": message,
-        "reason": reason || "unknown"
-      };
-    }
-    return {
-      "status": error_dict[name].status,
-      "statusText": error_dict[name].statusText,
-      "error": error_dict[name].error,
-      "message": message,
-      "reason": reason || error_dict[name].reason
-    };
-  }
-
-  /**
-   * Get the real type of an object
-   * @method type
-   * @param  {Any} value The value to check
-   * @return {String} The value type
-   */
-  function type(value) {
-    // returns "String", "Object", "Array", "RegExp", ...
-    return (/^\[object ([a-zA-Z]+)\]$/).exec(
-      Object.prototype.toString.call(value)
-    )[1];
-  }
-
-  /**
-   * Generate a new uuid
-   * @method generateUuid
-   * @return {string} The new uuid
-   */
-  function generateUuid() {
-    var S4 = function () {
-      var i, string = Math.floor(
-        Math.random() * 0x10000 /* 65536 */
-      ).toString(16);
-      for (i = string.length; i < 4; i += 1) {
-        string = "0" + string;
-      }
-      return string;
-    };
-    return S4() + S4() + "-" +
-      S4() + "-" +
-      S4() + "-" +
-      S4() + "-" +
-      S4() + S4() + S4();
-  }
-
-  /**
-   * Tool to get the date in W3C date format "2011-12-13T14:15:16+01:00"
-   *
-   * @param  {Any} date The new Date() parameter
-   * @return {String} The date in W3C date format
-   */
-  function w3cDate(date) {
-    var d = new Date(date), offset = -d.getTimezoneOffset();
-    return (
-      d.getFullYear() + "-" +
-        (d.getMonth() + 1) + "-" +
-        d.getDate() + "T" +
-        d.getHours() + ":" +
-        d.getMinutes() + ":" +
-        d.getSeconds() +
-        (offset < 0 ? "-" : "+") +
-        (offset / 60) + ":" +
-        (offset % 60)
-    ).replace(/[0-9]+/g, function (found) {
-      if (found.length < 2) {
-        return '0' + found;
-      }
-      return found;
-    });
+  if (typeof exports === 'object') {
+    return module(
+      exports,
+      require('jio'),
+      require('rsvp'),
+      require('complex_queries')
+    );
   }
+  window.index_storage = {};
+  module(window.index_storage, jIO, RSVP, complex_queries);
+}([
+  'exports',
+  'jio',
+  'rsvp',
+  'complex_queries'
+], function (exports, jIO, RSVP, complex_queries) {
+  "use strict";
 
   /**
    * A JSON Index manipulator
@@ -314,7 +206,7 @@
      */
     that.put = function (meta) {
       var k, needed_meta = {}, ok = false;
-      if (typeof meta._id !== "string" && meta._id !== "") {
+      if (typeof meta._id !== "string" || meta._id === "") {
         throw new TypeError("Corrupted Metadata");
       }
       for (k in meta) {
@@ -359,7 +251,8 @@
         throw new TypeError("Corrupted Metadata");
       }
       if (typeof that._location[meta._id] !== "number") {
-        throw new ReferenceError("Not Found");
+        // throw new ReferenceError("Not Found");
+        return;
       }
       that._database[that._location[meta._id]] = null;
       that._free.push(that._location[meta._id]);
@@ -388,7 +281,8 @@
       for (id in that._location) {
         if (that._location.hasOwnProperty(id)) {
           database_meta = that._database[that._location[id]];
-          if (type(database_meta) !== "Object" ||
+          if (typeof database_meta !== 'object' ||
+              Object.getPrototypeOf(database_meta || []) !== Object.prototype ||
               database_meta._id !== id) {
             throw new TypeError("Corrupted Index");
           }
@@ -421,8 +315,11 @@
 
     that.checkDocument = function (doc) {
       var i, key, db_doc;
-      if (typeof that._location[doc._id] !== "number" ||
-          (db_doc = that._database(that._location[doc._id])._id) !== doc._id) {
+      if (typeof that._location[doc._id] !== "number") {
+        throw new TypeError("Different Index");
+      }
+      db_doc = that._database(that._location[doc._id])._id;
+      if (db_doc !== doc._id) {
         throw new TypeError("Different Index");
       }
       for (i = 0; i < that._indexing.length; i += 1) {
@@ -442,12 +339,13 @@
       var i = 0, meta;
       that._free = [];
       that._location = {};
-      if (type(that._database) !== "Array") {
+      if (!Array.isArray(that._database)) {
         that._database = [];
       }
       while (i < that._database.length) {
         meta = that._database[i];
-        if (type(meta) === "Object" &&
+        if (typeof meta === 'object' &&
+            Object.getPrototypeOf(meta || []) === Object.prototype &&
             typeof meta._id === "string" && meta._id !== "" &&
             !that._location[meta._id]) {
           that._location[meta._id] = i;
@@ -461,10 +359,10 @@
     /**
      * Returns the serialized version of this object (not cloned)
      *
-     * @method serialized
+     * @method toJSON
      * @return {Object} The serialized version
      */
-    that.serialized = function () {
+    that.toJSON = function () {
       return {
         "indexing": that._indexing,
         "free": that._free,
@@ -481,502 +379,480 @@
   }
 
   /**
-   * The JIO index storage constructor
+   * Return the similarity percentage (1 >= p >= 0) between two index lists.
+   *
+   * @param  {Array} list_a An index list
+   * @param  {Array} list_b Another index list
+   * @return {Number} The similarity percentage
    */
-  function indexStorage(spec, my) {
-    var that, priv = {};
+  function similarityPercentage(list_a, list_b) {
+    var ai, bi, count = 0;
+    for (ai = 0; ai < list_a.length; ai += 1) {
+      for (bi = 0; bi < list_b.length; bi += 1) {
+        if (list_a[ai] === list_b[bi]) {
+          count += 1;
+          break;
+        }
+      }
+    }
+    return count / (list_a.length > list_b.length ?
+                    list_a.length : list_b.length);
+  }
 
-    that = my.basicStorage(spec, my);
+  /**
+   * The JIO index storage constructor
+   *
+   * @class IndexStorage
+   * @constructor
+   */
+  function IndexStorage(spec) {
+    var i;
+    if (!Array.isArray(spec.indices)) {
+      throw new TypeError("IndexStorage 'indices' must be an array of " +
+                          "objects.");
+    }
+    this._indices = spec.indices;
+    if (typeof spec.sub_storage !== 'object' ||
+        Object.getPrototypeOf(spec.sub_storage || []) !== Object.prototype) {
+      throw new TypeError("IndexStorage 'sub_storage' must be a storage " +
+                          "description.");
+    }
+    // check indices IDs
+    for (i = 0; i < this._indices.length; i += 1) {
+      if (typeof this._indices[i].id !== "string" ||
+          this._indices[i].id === "") {
+        throw new TypeError("IndexStorage " +
+                            "'indices[x].id' must be a non empty string");
+      }
+      if (!Array.isArray(this._indices[i].index)) {
+        throw new TypeError("IndexStorage " +
+                            "'indices[x].index' must be a string array");
+      }
+    }
+    this._sub_storage = spec.sub_storage;
+  }
 
-    priv.indices = spec.indices;
-    priv.sub_storage = spec.sub_storage;
+  /**
+   * Select the good index to use according to a select list.
+   *
+   * @method selectIndex
+   * @param  {Array} select_list An array of strings
+   * @return {Number} The index index
+   */
+  IndexStorage.prototype.selectIndex = function (select_list) {
+    var i, tmp, selector = {"index": 0, "similarity": 0};
+    for (i = 0; i < this._indices.length; i += 1) {
+      tmp = similarityPercentage(select_list, this._indices[i].index);
+      if (tmp > selector.similarity) {
+        selector.index = i;
+        selector.similarity = tmp;
+      }
+    }
+    return selector.index;
+  };
 
-    // Overrides
+  IndexStorage.prototype.getIndexDatabase = function (command, index) {
+    index = this._indices[index];
+    function makeNewIndex() {
+      return new JSONIndex({
+        "_id": index.id,
+        "_attachment": index.attachment || "body",
+        "indexing": index.index
+      });
+    }
+    return command.storage(
+      index.sub_storage || this._sub_storage
+    ).getAttachment({
+      "_id": index.id,
+      "_attachment": index.attachment || "body"
+    }).then(function (response) {
+      return jIO.util.readBlobAsText(response.data);
+    }).then(function (e) {
+      try {
+        e = JSON.parse(e.target.result);
+        e._id = index.id;
+        e._attachment = index.attachment || "body";
+      } catch (e1) {
+        return makeNewIndex();
+      }
+      return new JSONIndex(e);
+    }, function (err) {
+      if (err.status === 404) {
+        return makeNewIndex();
+        // go back to fulfillment channel
+      }
+      throw err;
+      // propagate err
+    });
+  };
 
-    that.specToStore = function () {
-      return {
-        "indices": priv.indices,
-        "sub_storage": priv.sub_storage
-      };
-    };
+  IndexStorage.prototype.getIndexDatabases = function (command) {
+    var i, promises = [];
+    for (i = 0; i < this._indices.length; i += 1) {
+      promises[promises.length] = this.getIndexDatabase(command, i);
+    }
+    return RSVP.all(promises);
+  };
 
-    /**
-     * Return the similarity percentage (1 >= p >= 0) between two index lists.
-     *
-     * @method similarityPercentage
-     * @param  {Array} list_a An index list
-     * @param  {Array} list_b Another index list
-     * @return {Number} The similarity percentage
-     */
-    priv.similarityPercentage = function (list_a, list_b) {
-      var ai, bi, count = 0;
-      for (ai = 0; ai < list_a.length; ai += 1) {
-        for (bi = 0; bi < list_b.length; bi += 1) {
-          if (list_a[ai] === list_b[bi]) {
-            count += 1;
-          }
-        }
+  IndexStorage.prototype.storeIndexDatabase = function (command, database,
+                                                        index) {
+    var that = this;
+    index = this._indices[index];
+    function putAttachment() {
+      return command.storage(
+        index.sub_storage || that._sub_storage
+      ).putAttachment({
+        "_id": index.id,
+        "_attachment": index.attachment || "body",
+        "_data": JSON.stringify(database),
+        "_content_type": "application/json"
+      });
+    }
+    function createDatabaseAndPutAttachmentIfPossible(err) {
+      if (err.status === 404) {
+        return command.storage(
+          index.sub_storage || that._sub_storage
+        ).post({
+          "_id": index.id
+          // XXX add metadata to document if necessary
+        }).then(putAttachment, null, function () {
+          throw null; // stop post progress propagation
+        });
       }
-      return count / (list_a.length > list_b.length ?
-                      list_a.length : list_b.length);
-    };
+      throw err;
+    }
+    return putAttachment().
+      then(null, createDatabaseAndPutAttachmentIfPossible);
+  };
 
-    /**
-     * Select the good index to use according to a select list.
-     *
-     * @method selectIndex
-     * @param  {Array} select_list An array of strings
-     * @return {Number} The index index
-     */
-    priv.selectIndex = function (select_list) {
-      var i, tmp, selector = {"index": 0, "similarity": 0};
-      for (i = 0; i < priv.indices.length; i += 1) {
-        tmp = priv.similarityPercentage(select_list,
-                                        priv.indices[i].index);
-        if (tmp > selector.similarity) {
-          selector.index = i;
-          selector.similarity = tmp;
-        }
+  IndexStorage.prototype.storeIndexDatabases = function (command, databases) {
+    var i, promises = [];
+    for (i = 0; i < this._indices.length; i += 1) {
+      if (databases[i] !== undefined) {
+        promises[promises.length] =
+          this.storeIndexDatabase(command, databases[i], i);
       }
-      return selector.index;
-    };
+    }
+    return RSVP.all(promises);
+  };
 
-    /**
-     * Get a database
-     *
-     * @method getIndexDatabase
-     * @param  {Object} option The command option
-     * @param  {Number} number The location in priv.indices
-     * @param  {Function} callback The callback
-     */
-    priv.getIndexDatabase = function (option, number, callback) {
-      that.addJob(
-        "getAttachment",
-        priv.indices[number].sub_storage || priv.sub_storage,
-        {
-          "_id": priv.indices[number].id,
-          "_attachment": priv.indices[number].attachment || "body"
-        },
-        option,
-        function (response) {
-          try {
-            response = JSON.parse(response);
-            response._id = priv.indices[number].id;
-            response._attachment = priv.indices[number].attachment || "body";
-            callback(new JSONIndex(response));
-          } catch (e) {
-            return that.error(generateErrorObject(
-              e.message,
-              "Repair is necessary",
-              "corrupt"
-            ));
-          }
-        },
-        function (err) {
-          if (err.status === 404) {
-            callback(new JSONIndex({
-              "_id": priv.indices[number].id,
-              "_attachment": priv.indices[number].attachment || "body",
-              "indexing": priv.indices[number].index
-            }));
-            return;
-          }
-          err.message = "Unable to get index database.";
-          that.error(err);
-        }
-      );
-    };
 
-    /**
-     * Gets a list containing all the databases set in the storage description.
-     *
-     * @method getIndexDatabaseList
-     * @param  {Object} option The command option
-     * @param  {Function} callback The result callback(database_list)
-     */
-    priv.getIndexDatabaseList = function (option, callback) {
-      var i, count = 0, callbacks = {}, response_list = [];
-      callbacks.error = function (index) {
-        return function (err) {
-          if (err.status === 404) {
-            response_list[index] = new JSONIndex({
-              "_id": priv.indices[index].id,
-              "_attachment": priv.indices[index].attachment || "body",
-              "indexing": priv.indices[index].index
-            });
-            count += 1;
-            if (count === priv.indices.length) {
-              callback(response_list);
-            }
-            return;
-          }
-          err.message = "Unable to get index database.";
-          that.error(err);
-        };
-      };
-      callbacks.success = function (index) {
-        return function (response) {
-          try {
-            response = JSON.parse(response);
-            response._id = priv.indices[index].id;
-            response._attachment = priv.indices[index].attachment || "body";
-            response_list[index] = new JSONIndex(response);
-          } catch (e) {
-            return that.error(generateErrorObject(
-              e.message,
-              "Repair is necessary",
-              "corrupt"
-            ));
-          }
-          count += 1;
-          if (count === priv.indices.length) {
-            callback(response_list);
-          }
-        };
-      };
-      for (i = 0; i < priv.indices.length; i += 1) {
-        that.addJob(
-          "getAttachment",
-          priv.indices[i].sub_storage || priv.sub_storage,
-          {
-            "_id": priv.indices[i].id,
-            "_attachment": priv.indices[i].attachment || "body"
-          },
-          option,
-          callbacks.success(i),
-          callbacks.error(i)
-        );
+  /**
+   * Generic method for 'post', 'put', 'get' and 'remove'. It delegates the
+   * command to the sub storage and update the databases.
+   *
+   * @method genericCommand
+   * @param  {String} method The method to use
+   * @param  {Object} command The JIO command
+   * @param  {Object} metadata The metadata to post
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.genericCommand = function (method, command,
+                                                    metadata, option) {
+    var that = this, generic_response;
+    function updateAndStoreIndexDatabases(responses) {
+      var i, database_list = responses[0];
+      generic_response = responses[1];
+      if (method === 'get') {
+        jIO.util.dictUpdate(metadata, generic_response.data);
       }
-    };
-
-    /**
-     * Saves all the databases to the remote(s).
-     *
-     * @method storeIndexDatabaseList
-     * @param  {Array} database_list The database list
-     * @param  {Object} option The command option
-     * @param  {Function} callback The result callback(err, response)
-     */
-    priv.storeIndexDatabaseList = function (database_list, option, callback) {
-      var i, count = 0, count_max = 0;
-      function onAttachmentResponse(response) {
-        count += 1;
-        if (count === count_max) {
-          callback({"ok": true});
+      metadata._id = generic_response.id;
+      if (method === 'remove') {
+        for (i = 0; i < database_list.length; i += 1) {
+          database_list[i].remove(metadata);
         }
-      }
-      function onAttachmentError(err) {
-        err.message = "Unable to store index database.";
-        that.error(err);
-      }
-      function putAttachment(i) {
-        that.addJob(
-          "putAttachment",
-          priv.indices[i].sub_storage || priv.sub_storage,
-          {
-            "_id": database_list[i]._id,
-            "_attachment": database_list[i]._attachment,
-            "_data": JSON.stringify(database_list[i].serialized()),
-            "_mimetype": "application/json"
-          },
-          option,
-          onAttachmentResponse,
-          onAttachmentError
-        );
-      }
-      function post(i) {
-        var doc = priv.indices[i].metadata || {};
-        doc._id = database_list[i]._id;
-        that.addJob(
-          "post", // with id
-          priv.indices[i].sub_storage || priv.sub_storage,
-          doc,
-          option,
-          function (response) {
-            putAttachment(i);
-          },
-          function (err) {
-            if (err.status === 409) {
-              return putAttachment(i);
-            }
-            err.message = "Unable to store index database.";
-            that.error(err);
-          }
-        );
-      }
-      for (i = 0; i < priv.indices.length; i += 1) {
-        if (database_list[i] !== undefined) {
-          count_max += 1;
-          post(i);
+      } else {
+        for (i = 0; i < database_list.length; i += 1) {
+          database_list[i].put(metadata);
         }
       }
-    };
+      return that.storeIndexDatabases(command, database_list);
+    }
 
-    /**
-     * A generic request method which delegates the request to the sub storage.
-     * On response, it will index the document from the request and update all
-     * the databases.
-     *
-     * @method genericRequest
-     * @param  {Command} command The JIO command
-     * @param  {Function} method The request method
-     */
-    priv.genericRequest = function (command, method) {
-      var doc = command.cloneDoc(), option = command.cloneOption();
-      that.addJob(
-        method,
-        priv.sub_storage,
-        doc,
-        option,
-        function (response) {
-          switch (method) {
-          case "post":
-          case "put":
-          case "remove":
-            doc._id = response.id;
-            priv.getIndexDatabaseList(option, function (database_list) {
-              var i;
-              switch (method) {
-              case "post":
-              case "put":
-                for (i = 0; i < database_list.length; i += 1) {
-                  database_list[i].put(doc);
-                }
-                break;
-              case "remove":
-                for (i = 0; i < database_list.length; i += 1) {
-                  database_list[i].remove(doc);
-                }
-                break;
-              default:
-                break;
-              }
-              priv.storeIndexDatabaseList(database_list, option, function () {
-                that.success({"ok": true, "id": doc._id});
-              });
-            });
-            break;
-          default:
-            that.success(response);
-            break;
-          }
-        },
-        function (err) {
-          return that.error(err);
-        }
-      );
-    };
+    function allProgress(progress) {
+      if (progress.index === 1) {
+        progress.value.percentage *= 0.7; // 0 to 70%
+        command.notify(progress.value);
+      }
+      throw null; // stop propagation
+    }
 
-    /**
-     * Post the document metadata and update the index
-     * @method post
-     * @param  {object} command The JIO command
-     */
-    that.post = function (command) {
-      priv.genericRequest(command, 'post');
-    };
+    function success() {
+      command.success(generic_response);
+    }
 
-    /**
-     * Update the document metadata and update the index
-     * @method put
-     * @param  {object} command The JIO command
-     */
-    that.put = function (command) {
-      priv.genericRequest(command, 'put');
-    };
+    function storeProgress(progress) {
+      progress.percentage = (0.3 * progress.percentage) + 70; // 70 to 100%
+      command.notify(progress);
+    }
 
-    /**
-     * Add an attachment to a document (no index modification)
-     * @method putAttachment
-     * @param  {object} command The JIO command
-     */
-    that.putAttachment = function (command) {
-      priv.genericRequest(command, 'putAttachment');
-    };
+    RSVP.all([
+      this.getIndexDatabases(command),
+      command.storage(this._sub_storage)[method](metadata, option)
+    ]).then(updateAndStoreIndexDatabases, null, allProgress).
+      then(success, command.error, storeProgress);
+  };
 
-    /**
-     * Get the document metadata
-     * @method get
-     * @param  {object} command The JIO command
-     */
-    that.get = function (command) {
-      priv.genericRequest(command, 'get');
-    };
+  /**
+   * Post the document metadata and update the index
+   *
+   * @method post
+   * @param  {Object} command The JIO command
+   * @param  {Object} metadata The metadata to post
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.post = function (command, metadata, option) {
+    this.genericCommand('post', command, metadata, option);
+  };
 
-    /**
-     * Get the attachment.
-     * @method getAttachment
-     * @param  {object} command The JIO command
-     */
-    that.getAttachment = function (command) {
-      priv.genericRequest(command, 'getAttachment');
-    };
+  /**
+   * Update the document metadata and update the index
+   *
+   * @method put
+   * @param  {Object} command The JIO command
+   * @param  {Object} metadata The metadata to put
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.put = function (command, metadata, option) {
+    this.genericCommand('put', command, metadata, option);
+  };
 
-    /**
-     * Remove document - removing documents updates index!.
-     * @method remove
-     * @param  {object} command The JIO command
-     */
-    that.remove = function (command) {
-      priv.genericRequest(command, 'remove');
-    };
+  /**
+   * Add an attachment to a document (no index modification)
+   *
+   * @method putAttachment
+   * @param  {Object} command The JIO command
+   * @param  {Object} param The command parameters
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.putAttachment = function (command, param, option) {
+    command.storage(this._sub_storage).putAttachment(param, option).
+      then(command.success, command.error, command.notify);
+  };
 
-    /**
-     * Remove attachment
-     * @method removeAttachment
-     * @param  {object} command The JIO command
-     */
-    that.removeAttachment = function (command) {
-      priv.genericRequest(command, 'removeAttachment');
-    };
+  /**
+   * Get the document metadata
+   *
+   * @method get
+   * @param  {Object} command The JIO command
+   * @param  {Object} param The command parameters
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.get = function (command, param, option) {
+    this.genericCommand('get', command, param, option);
+  };
 
-    /**
-     * Gets a document list from the substorage
-     * Options:
-     * - {boolean} include_docs Also retrieve the actual document content.
-     * @method allDocs
-     * @param  {object} command The JIO command
-     */
-    that.allDocs = function (command) {
-      var option = command.cloneOption(),
-        index = priv.selectIndex(option.select_list || []);
-      // Include docs option is ignored, if you want to get all the document,
-      // don't use index storage!
+  /**
+   * Get the attachment.
+   *
+   * @method getAttachment
+   * @param  {Object} command The JIO command
+   * @param  {Object} param The command parameters
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.getAttachment = function (command, param, option) {
+    command.storage(this._sub_storage).getAttachment(param, option).
+      then(command.success, command.error, command.notify);
+  };
 
-      option.select_list = option.select_list || [];
-      option.select_list.push("_id");
-      priv.getIndexDatabase(option, index, function (db) {
-        var i, id;
-        db = db._database;
-        complex_queries.QueryFactory.create(option.query || '').
-          exec(db, option);
-        for (i = 0; i < db.length; i += 1) {
-          id = db[i]._id;
-          delete db[i]._id;
-          db[i] = {
-            "id": id,
-            "key": id,
-            "value": db[i],
-          };
-        }
-        that.success({"total_rows": db.length, "rows": db});
-      });
-    };
+  /**
+   * Remove document - removing documents updates index!.
+   *
+   * @method remove
+   * @param  {Object} command The JIO command
+   * @param  {Object} param The command parameters
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.remove = function (command, param, option) {
+    this.genericCommand('remove', command, param, option);
+  };
 
-    that.check = function (command) {
-      that.repair(command, true);
-    };
+  /**
+   * Remove attachment
+   *
+   * @method removeAttachment
+   * @param  {Object} command The JIO command
+   * @param  {Object} param The command parameters
+   * @param  {Object} option The command option
+   */
+  IndexStorage.prototype.removeAttachment = function (command, param, option) {
+    command.storage(this._sub_storage).removeAttachment(param, option).
+      then(command.success, command.error, command.notify);
+  };
 
-    priv.repairIndexDatabase = function (command, index, just_check) {
-      var i, option = command.cloneOption();
-      that.addJob(
-        'allDocs',
-        priv.sub_storage,
-        {},
-        {'include_docs': true},
-        function (response) {
-          var db_list = [], db = new JSONIndex({
-            "_id": command.getDocId(),
-            "_attachment": priv.indices[index].attachment || "body",
-            "indexing": priv.indices[index].index
-          });
-          for (i = 0; i < response.rows.length; i += 1) {
-            db.put(response.rows[i].doc);
-          }
-          db_list[index] = db;
-          if (just_check) {
-            priv.getIndexDatabase(option, index, function (current_db) {
-              if (db.equals(current_db)) {
-                return that.success({"ok": true, "id": command.getDocId()});
-              }
-              return that.error(generateErrorObject(
-                "Different Index",
-                "Check failed",
-                "corrupt index database"
-              ));
-            });
-          } else {
-            priv.storeIndexDatabaseList(db_list, {}, function () {
-              that.success({"ok": true, "id": command.getDocId()});
-            });
-          }
-        },
-        function (err) {
-          err.message = "Unable to repair the index database";
-          that.error(err);
-        }
-      );
-    };
+  /**
+   * Gets a document list from the substorage
+   * Options:
+   * - {boolean} include_docs Also retrieve the actual document content.
+   * @method allDocs
+   * @param  {object} command The JIO command
+   */
+  IndexStorage.prototype.allDocs = function (command, param, option) { // XXX
+    /*jslint unparam: true */
+    var index = this.selectIndex(option.select_list || []), delete_id;
 
-    priv.repairDocument = function (command, just_check) {
-      var i, option = command.cloneOption();
-      that.addJob(
-        "get",
-        priv.sub_storage,
-        command.cloneDoc(),
-        {},
-        function (response) {
-          response._id = command.getDocId();
-          priv.getIndexDatabaseList(option, function (database_list) {
-            if (just_check) {
-              for (i = 0; i < database_list.length; i += 1) {
-                try {
-                  database_list[i].checkDocument(response);
-                } catch (e) {
-                  return that.error(generateErrorObject(
-                    e.message,
-                    "Check failed",
-                    "corrupt index database"
-                  ));
-                }
-              }
-              that.success({"_id": command.getDocId(), "ok": true});
-            } else {
-              for (i = 0; i < database_list.length; i += 1) {
-                database_list[i].put(response);
-              }
-              priv.storeIndexDatabaseList(database_list, option, function () {
-                that.success({"ok": true, "id": command.getDocId()});
-              });
-            }
-          });
-        },
-        function (err) {
-          err.message = "Unable to repair document";
-          return that.error(err);
-        }
-      );
-    };
+    // Include docs option is ignored, if you want to get all the document,
+    // don't use index storage!
 
-    that.repair = function (command, just_check) {
-      var database_index = -1, i;
-      for (i = 0; i < priv.indices.length; i += 1) {
-        if (priv.indices[i].id === command.getDocId()) {
-          database_index = i;
-          break;
+    option.select_list = (
+      Array.isArray(option.select_list) ? option.select_list : []
+    );
+    if (option.select_list.indexOf("_id") === -1) {
+      option.select_list.push("_id");
+      delete_id = true;
+    }
+    this.getIndexDatabase(command, index).then(function (db) {
+      var i, id;
+      db = db._database;
+      complex_queries.QueryFactory.create(option.query || '').
+        exec(db, option);
+      for (i = 0; i < db.length; i += 1) {
+        id = db[i]._id;
+        if (delete_id) {
+          delete db[i]._id;
         }
+        db[i] = {
+          "id": id,
+          "value": db[i]
+        };
       }
-      that.addJob(
-        "repair",
-        priv.sub_storage,
-        command.cloneDoc(),
-        command.cloneOption(),
-        function (response) {
-          if (database_index !== -1) {
-            priv.repairIndexDatabase(command, database_index, just_check);
-          } else {
-            priv.repairDocument(command, just_check);
-          }
-        },
-        function (err) {
-          err.message = "Could not repair sub storage";
-          that.error(err);
-        }
-      );
-    };
+      command.success(200, {"data": {"total_rows": db.length, "rows": db}});
+    }, function (err) {
+      if (err.status === 404) {
+        return command.success(200, {"data": {"total_rows": 0, "rows": []}});
+      }
+      command.error(err);
+    });
+  };
 
-    return that;
-  }
+  // IndexStorage.prototype.check = function (command, param, option) { // XXX
+  //   this.repair(command, true, param, option);
+  // };
+
+  // IndexStorage.prototype.repairIndexDatabase = function (
+  //   command,
+  //   index,
+  //   just_check,
+  //   param,
+  //   option
+  // ) { // XXX
+  //   var i, that = this;
+  //   command.storage(this._sub_storage).allDocs({'include_docs': true}).then(
+  //     function (response) {
+  //       var db_list = [], db = new JSONIndex({
+  //         "_id": param._id,
+  //         "_attachment": that._indices[index].attachment || "body",
+  //         "indexing": that._indices[index].index
+  //       });
+  //       for (i = 0; i < response.rows.length; i += 1) {
+  //         db.put(response.rows[i].doc);
+  //       }
+  //       db_list[index] = db;
+  //       if (just_check) {
+  //       this.getIndexDatabase(command, option, index, function (current_db) {
+  //           if (db.equals(current_db)) {
+  //             return command.success({"ok": true, "id": param._id});
+  //           }
+  //           return command.error(
+  //             "conflict",
+  //             "corrupted",
+  //             "Database is not up to date"
+  //           );
+  //         });
+  //       } else {
+  //         that.storeIndexDatabaseList(command, db_list, {}, function () {
+  //           command.success({"ok": true, "id": param._id});
+  //         });
+  //       }
+  //     },
+  //     function (err) {
+  //       err.message = "Unable to repair the index database";
+  //       command.error(err);
+  //     }
+  //   );
+  // };
+
+  // IndexStorage.prototype.repairDocument = function (
+  //   command,
+  //   just_check,
+  //   param,
+  //   option
+  // ) { // XXX
+  //   var i, that = this;
+  //   command.storage(this._sub_storage).get(param, {}).then(
+  //     function (response) {
+  //       response._id = param._id;
+  //       that.getIndexDatabaseList(command, option, function (database_list) {
+  //         if (just_check) {
+  //           for (i = 0; i < database_list.length; i += 1) {
+  //             try {
+  //               database_list[i].checkDocument(response);
+  //             } catch (e) {
+  //               return command.error(
+  //                 "conflict",
+  //                 e.message,
+  //                 "Corrupt index database"
+  //               );
+  //             }
+  //           }
+  //           command.success({"_id": param._id, "ok": true});
+  //         } else {
+  //           for (i = 0; i < database_list.length; i += 1) {
+  //             database_list[i].put(response);
+  //           }
+  //           that.storeIndexDatabaseList(
+  //             command,
+  //             database_list,
+  //             option,
+  //             function () {
+  //               command.success({"ok": true, "id": param._id});
+  //             }
+  //           );
+  //         }
+  //       });
+  //     },
+  //     function (err) {
+  //       err.message = "Unable to repair document";
+  //       return command.error(err);
+  //     }
+  //   );
+  // };
+
+  // IndexStorage.prototype.repair = function (command, just_check, param,
+  //                                           option) { // XXX
+  //   var database_index = -1, i, that = this;
+  //   for (i = 0; i < this._indices.length; i += 1) {
+  //     if (this._indices[i].id === param._id) {
+  //       database_index = i;
+  //       break;
+  //     }
+  //   }
+  //   command.storage(this._sub_storage).repair(param, option).then(
+  //     function () {
+  //       if (database_index !== -1) {
+  //         that.repairIndexDatabase(
+  //           command,
+  //           database_index,
+  //           just_check,
+  //           param,
+  //           option
+  //         );
+  //       } else {
+  //         that.repairDocument(command, just_check, param, option);
+  //       }
+  //     },
+  //     function (err) {
+  //       err.message = "Could not repair sub storage";
+  //       command.error(err);
+  //     }
+  //   );
+  // };
+
+  jIO.addStorage("indexed", IndexStorage);
+
+  exports.createDescription = function () {
+    // XXX
+    return;
+  };
 
-  jIO.addStorageType("indexed", indexStorage);
 }));
diff --git a/test/jio.storage/indexstorage.tests.js b/test/jio.storage/indexstorage.tests.js
index 9f317ca0f1a5017b41ca142e7a8c4a961371e553..f2e88b309b50df34eef93fe9670f17240b1c727e 100644
--- a/test/jio.storage/indexstorage.tests.js
+++ b/test/jio.storage/indexstorage.tests.js
@@ -1,5 +1,6 @@
 /*jslint indent: 2, maxlen: 80, nomen: true */
-/*global define, jIO, jio_tests, test, ok, deepEqual, sinon */
+/*global define, module, test_util, RSVP, jIO, local_storage, test, ok,
+  deepEqual, stop, start */
 
 // define([module_name], [dependencies], module);
 (function (dependencies, module) {
@@ -7,1108 +8,621 @@
   if (typeof define === 'function' && define.amd) {
     return define(dependencies, module);
   }
-  module(jIO, jio_tests);
-}(['jio', 'jio_tests', 'localstorage', 'indexstorage'], function (jIO, util) {
+  module(test_util, RSVP, jIO, local_storage);
+}([
+  'test_util',
+  'rsvp',
+  'jio',
+  'localstorage',
+  'indexstorage'
+], function (util, RSVP, jIO, local_storage) {
   "use strict";
 
-  function generateTools() {
-    return {
-      clock: sinon.useFakeTimers(),
-      spy: util.ospy,
-      tick: util.otick
-    };
-  }
-
-  module("IndexStorage");
-
-  test("Post", function () {
-
-    var o = generateTools();
-
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["title"]},
-        {"id": "B", "index": ["title", "year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "ipost",
-        "application_name": "ipost"
-      }
+  function success(promise) {
+    return new RSVP.Promise(function (resolve, reject, notify) {
+      /*jslint unparam: true*/
+      promise.then(resolve, resolve, notify);
+    }, function () {
+      promise.cancel();
     });
+  }
 
-    o.getAttachmentCallback = function (err, response) {
-      if (response) {
-        try {
-          response = JSON.parse(response);
-        } catch (e) {
-          response = "PARSE ERROR " + response;
+  /**
+   * sequence(thens): Promise
+   *
+   * Executes a sequence of *then* callbacks. It acts like
+   * `smth().then(callback).then(callback)...`. The first callback is called
+   * with no parameter.
+   *
+   * Elements of `thens` array can be a function or an array contaning at most
+   * three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
+   *
+   * When `cancel()` is executed, each then promises are cancelled at the same
+   * time.
+   *
+   * @param  {Array} thens An array of *then* callbacks
+   * @return {Promise} A new promise
+   */
+  function sequence(thens) {
+    var promises = [];
+    return new RSVP.Promise(function (resolve, reject, notify) {
+      var i;
+      promises[0] = new RSVP.Promise(function (resolve) {
+        resolve();
+      });
+      for (i = 0; i < thens.length; i += 1) {
+        if (Array.isArray(thens[i])) {
+          promises[i + 1] = promises[i].
+            then(thens[i][0], thens[i][1], thens[i][2]);
+        } else {
+          promises[i + 1] = promises[i].then(thens[i]);
         }
       }
-      o.f(err, response);
-    };
-
-    // post without id
-    o.spy(o, "jobstatus", "done", "Post without id");
-    o.jio.post({}, function (err, response) {
-      o.id = (response || {}).id;
-      o.f(err, response);
-    });
-    o.tick(o);
-
-    // post non empty document
-    o.doc = {"_id": "some_id", "title": "My Title",
-             "year": 2000, "hey": "def"};
-    o.spy(o, "value", {"ok": true, "id": "some_id"}, "Post document");
-    o.jio.post(o.doc, o.f);
-    o.tick(o);
-
-    // check document
-    o.fakeIndexA = {
-      "indexing": ["title"],
-      "free": [],
-      "location": {
-        "some_id": 0
-      },
-      "database": [
-        {"_id": "some_id", "title": "My Title"}
-      ]
-    };
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.fakeIndexB = {
-      "indexing": ["title", "year"],
-      "free": [],
-      "location": {
-        "some_id": 0
-      },
-      "database": [
-        {"_id": "some_id", "title": "My Title", "year": 2000}
-      ]
-    };
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // post with escapable characters
-    o.doc = {
-      "_id": "other_id",
-      "title": "myPost2",
-      "findMeA": "keyword_*§$%&/()=?",
-      "findMeB": "keyword_|ð@ł¶đæðſæðæſ³"
-    };
-    o.spy(o, "value", {"ok": true, "id": "other_id"},
-          "Post with escapable characters");
-    o.jio.post(o.doc, o.f);
-    o.tick(o);
-
-    // post and document already exists
-    o.doc = {
-      "_id": "some_id",
-      "title": "myPost3",
-      "findMeA": "keyword_ghi",
-      "findMeB": "keyword_jkl"
-    };
-    o.spy(o, "status", 409, "Post and document already exists");
-    o.jio.post(o.doc, o.f);
-    o.tick(o);
-
-    util.closeAndcleanUpJio(o.jio);
-  });
-
-  test("Put", function () {
-
-    var o = generateTools();
-
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["author"]},
-        {"id": "B", "index": ["year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "iput",
-        "application_name": "iput"
+      promises[i].then(resolve, reject, notify);
+    }, function () {
+      var i;
+      for (i = 0; i < promises.length; i += 1) {
+        promises[i].cancel();
       }
     });
+  }
 
-    o.getAttachmentCallback = function (err, response) {
-      if (response) {
-        try {
-          response = JSON.parse(response);
-        } catch (e) {
-          response = "PARSE ERROR " + response;
-        }
-      }
-      o.f(err, response);
-    };
-
-    // put without id
-    // error 20 -> document id required
-    o.spy(o, "status", 20, "Put without id");
-    o.jio.put({}, o.f);
-    o.tick(o);
-
-    // put non empty document
-    o.doc = {"_id": "put1", "title": "myPut1", "author": "John Doe"};
-    o.spy(o, "value", {"ok": true, "id": "put1"}, "Put-create document");
-    o.jio.put(o.doc, o.f);
-    o.tick(o);
-
-    // check index file
-    o.fakeIndexA = {
-      "indexing": ["author"],
-      "free": [],
-      "location": {
-        "put1": 0
-      },
-      "database": [{"_id": "put1", "author": "John Doe"}]
-    };
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.fakeIndexB = {
-      "indexing": ["year"],
-      "free": [],
-      "location": {},
-      "database": []
-    };
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // modify document - modify keyword on index!
-    o.doc = {"_id": "put1", "title": "myPuttter1", "author": "Jane Doe"};
-    o.spy(o, "value", {"ok": true, "id": "put1"}, "Modify existing document");
-    o.jio.put(o.doc, o.f);
-    o.tick(o);
-
-    // check index file
-    o.fakeIndexA.database[0].author = "Jane Doe";
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // add new document with same keyword!
-    o.doc = {"_id": "new_doc", "title": "myPut2", "author": "Jane Doe"};
-    o.spy(o, "value", {"ok": true, "id": "new_doc"},
-           "Add new document with same keyword");
-    o.jio.put(o.doc, o.f);
-    o.tick(o);
-
-    // check index file
-    o.fakeIndexA.location.new_doc = 1;
-    o.fakeIndexA.database.push({"_id": "new_doc", "author": "Jane Doe"});
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // add second keyword to index file
-    o.doc = {"_id": "put1", "title": "myPut2", "author": "Jane Doe",
-             "year": "1912"};
-    o.spy(o, "value", {"ok": true, "id": "put1"},
-           "add second keyword to index file");
-    o.jio.put(o.doc, o.f);
-    o.tick(o);
-
-    // check index file
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.fakeIndexB.location.put1 = 0;
-    o.fakeIndexB.database.push({"_id": "put1", "year": "1912"});
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // remove a keyword from an existing document
-    o.doc = {"_id": "new_doc", "title": "myPut2"};
-    o.spy(o, "value", {"ok": true, "id": "new_doc"},
-           "Remove keyword from existing document");
-    o.jio.put(o.doc, o.f);
-    o.tick(o);
-
-    // check index file
-    delete o.fakeIndexA.location.new_doc;
-    o.fakeIndexA.database[1] = null;
-    o.fakeIndexA.free.push(1);
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    util.closeAndcleanUpJio(o.jio);
-  });
+  module("IndexStorage");
 
-  test("Check & Repair", function () {
-    var o = generateTools(), i;
+  test("Scenario", function () {
 
-    o.jio = jIO.newJio({
+    var LOCAL_STORAGE_SPEC = local_storage.createDescription(
+      'indexstorage tests',
+      'scenario',
+      'memory'
+    ), INDEX_STORAGE_SPEC = {
       "type": "indexed",
       "indices": [
-        {"id": "A", "index": ["director"]},
-        {"id": "B", "index": ["year"]}
+        {"id": "A", "index": ["contributor"]},
+        {"id": "B", "index": ["author"]},
+        {"id": "C", "index": ["title"]},
+        {"id": "D", "index": ["title", "year"]}
       ],
-      "sub_storage": {
-        "type": "local",
-        "username": "indexstoragerepair"
-      }
-    });
+      "sub_storage": LOCAL_STORAGE_SPEC
+    }, option = {"workspace": {}}, shared = {}, jio_index, jio_local;
 
-    o.getAttachmentCallback = function (err, response) {
-      if (response) {
-        try {
-          response = JSON.parse(response);
-        } catch (e) {
-          response = "PARSE ERROR " + response;
-        }
-        delete response.location;
-        response.database.sort(function (a, b) {
-          return a._id < b._id ? -1 : a._id > b._id ? 1 : 0;
-        });
-      }
-      o.f(err, response);
-    };
-
-    o.fakeIndexA = {
-      "indexing": ["director"],
-      "free": [],
-      "database": []
-    };
-    o.fakeIndexB = {
-      "indexing": ["year"],
-      "free": [],
-      "database": []
-    };
-
-    for (i = 0; i < 10; i += 1) {
-      o.jio.put({
-        "_id": "id" + i,
-        "director": "D" + i,
-        "year": i,
-        "title": "T" + i
-      });
-
-      o.tmp = o.fakeIndexA.free.pop() || o.fakeIndexA.database.length;
-      o.fakeIndexA.database[o.tmp] = {"_id": "id" + i, "director": "D" + i};
+    jio_index = jIO.createJIO(INDEX_STORAGE_SPEC, option);
+    jio_local = jIO.createJIO(LOCAL_STORAGE_SPEC, option);
 
-      o.tmp = o.fakeIndexB.free.pop() || o.fakeIndexB.database.length;
-      o.fakeIndexB.database[o.tmp] = {"_id": "id" + i, "year": i};
+    function postNewDocument() {
+      return jio_index.post({"title": "Unique ID"});
     }
-    o.clock.tick(5000);
-
-    o.spy(o, "status", 40, "Check database");
-    o.jio.check({"_id": "A"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "status", 40, "Check database");
-    o.jio.check({"_id": "B"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "value", {"id": "A", "ok": true}, "Repair database");
-    o.jio.repair({"_id": "A"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "value", {"id": "B", "ok": true}, "Repair database");
-    o.jio.repair({"_id": "B"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "value", {"id": "A", "ok": true}, "Check database again");
-    o.jio.check({"_id": "A"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "value", {"id": "B", "ok": true}, "Check database again");
-    o.jio.check({"_id": "B"}, o.f);
-    o.tick(o);
-
-    // check index file
-    o.spy(o, "value", o.fakeIndexA, "Manually check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.spy(o, "value", o.fakeIndexB, "Manually check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.jio2 = jIO.newJio({"type": "local", "username": "indexstoragerepair"});
-
-    o.jio2.put({"_id": "blah", "title": "t", "year": "y", "director": "d"});
-    o.clock.tick(1000);
-    util.closeAndcleanUpJio(o.jio2);
-
-    o.fakeIndexA.database.unshift({"_id": "blah", "director": "d"});
-    o.fakeIndexB.database.unshift({"_id": "blah", "year": "y"});
-
-    o.spy(o, "status", 40, "Check Document");
-    o.jio.check({"_id": "blah"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "value", {"id": "blah", "ok": true}, "Repair Document");
-    o.jio.repair({"_id": "blah"}, o.f);
-    o.tick(o);
-
-    o.spy(o, "value", {"id": "blah", "ok": true}, "Check Document again");
-    o.jio.repair({"_id": "blah"}, o.f);
-    o.tick(o);
-
-    // check index file
-    o.spy(o, "value", o.fakeIndexA, "Manually check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.spy(o, "value", o.fakeIndexB, "Manually check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    util.closeAndcleanUpJio(o.jio);
-  });
 
-  test("PutAttachment", function () {
-
-    // not sure these need to be run, because the index does not change
-    // and only small modifications have been made to handle putAttachment
-    // tests are from localStorage putAttachment
-    var o = generateTools();
-
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["author"]},
-        {"id": "B", "index": ["year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "iputatt",
-        "application_name": "iputatt"
-      }
-    });
-
-    // putAttachment without doc id
-    // error 20 -> document id required
-    o.spy(o, "status", 20, "PutAttachment without doc id");
-    o.jio.putAttachment({}, o.f);
-    o.tick(o);
-
-    // putAttachment without attachment id
-    // error 22 -> attachment id required
-    o.spy(o, "status", 22, "PutAttachment without attachment id");
-    o.jio.putAttachment({"_id": "putattmt1"}, o.f);
-    o.tick(o);
-
-    // putAttachment without document
-    // error 404 -> not found
-    o.spy(o, "status", 404, "PutAttachment without document");
-    o.jio.putAttachment({"_id": "putattmt1", "_attachment": "putattmt2"}, o.f);
-    o.tick(o);
+    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;
+    }
 
-    // putAttachment with document
-    o.doc = {"_id": "putattmt1", "title": "myPutAttmt1"};
-    o.spy(o, "value", {"ok": true, "id": "putattmt1"},
-          "Put underlying document");
-    o.jio.put(o.doc, o.f);
-    o.tick(o);
+    function getCreatedDocument() {
+      return jio_index.get({"_id": shared.created_document_id});
+    }
 
-    o.spy(o, "value", {
-      "ok": true,
-      "id": "putattmt1",
-      "attachment": "putattmt2"
-    }, "PutAttachment with document, without data");
-    o.jio.putAttachment({"_id": "putattmt1", "_attachment": "putattmt2"}, o.f);
-    o.tick(o);
+    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");
+    }
 
-    // check document
-    deepEqual(util.jsonlocalstorage.getItem(
-      "jio/localstorage/iputatt/iputatt/putattmt1"
-    ), {
-      "_id": "putattmt1",
-      "title": "myPutAttmt1",
-      "_attachments": {
-        "putattmt2": {
-          "length": 0,
-          // md5("")
-          "digest": "md5-d41d8cd98f00b204e9800998ecf8427e"
-        }
-      }
-    }, "Check document");
+    // function postSpecificDocuments() {
+    //   return success(RSVP.all([
+    //     jio_index.post({"_id": "b", "title": "Bee", "year": 2013}),
+    //     jio_index.post({"_id": "ce", "contributor": "DCee"}),
+    //     jio_index.post({"_id": "dee", "format": "text/plain"})
+    //   ]));
+    // }
+
+    // function postSpecificDocumentsTest(answers) {
+    //   deepEqual(answers[0], {
+    //     "id": "b",
+    //     "method": "post",
+    //     "result": "success",
+    //     "status": 201,
+    //     "statusText": "Created"
+    //   }, "Post specific document 'b'");
+
+    //   deepEqual(answers[1], {
+    //     "id": "ce",
+    //     "method": "post",
+    //     "result": "success",
+    //     "status": 201,
+    //     "statusText": "Created"
+    //   }, "Post specific document 'ce'");
+
+    //   deepEqual(answers[2], {
+    //     "id": "dee",
+    //     "method": "post",
+    //     "result": "success",
+    //     "status": 201,
+    //     "statusText": "Created"
+    //   }, "Post specific document 'dee'");
+    // }
+
+    // XXX the 2 following functions should be replaced by the 2 commented
+    // previous ones (which don't work yet)
+    function postSpecificDocuments() {
+      return sequence([function () {
+        return jio_index.post({"_id": "b", "title": "Bee", "year": 2013});
+      }, function () {
+        return jio_index.post({"_id": "ce", "contributor": "DCee"});
+      }, function () {
+        return jio_index.post({"_id": "dee", "format": "text/plain"});
+      }]);
+    }
 
-    // check attachment
-    deepEqual(util.jsonlocalstorage.getItem(
-      "jio/localstorage/iputatt/iputatt/putattmt1/putattmt2"
-    ), "", "Check attachment");
+    function postSpecificDocumentsTest(last_answer) {
+      deepEqual(last_answer, {
+        "id": "dee",
+        "method": "post",
+        "result": "success",
+        "status": 201,
+        "statusText": "Created"
+      }, "Post documents: 'b', 'ce', 'dee' (testing 'dee' response only)");
+    }
 
-    // update attachment
-    o.spy(o, "value",
-          {"ok": true, "id": "putattmt1", "attachment": "putattmt2"},
-          "Update Attachment, with data");
-    o.jio.putAttachment({
-      "_id": "putattmt1",
-      "_attachment": "putattmt2",
-      "_data": "abc"
-    }, o.f);
-    o.tick(o);
+    function listDocumentsFromIndexContributor() {
+      return jio_index.allDocs({"select_list": ["contributor"]});
+    }
 
-    // check document
-    deepEqual(util.jsonlocalstorage.getItem(
-      "jio/localstorage/iputatt/iputatt/putattmt1"
-    ), {
-      "_id": "putattmt1",
-      "title": "myPutAttmt1",
-      "_attachments": {
-        "putattmt2": {
-          "length": 3,
-          // md5("abc")
-          "digest": "md5-900150983cd24fb0d6963f7d28e17f72"
-        }
+    function listDocumentsFromIndexContributorTest(answer) {
+      if (answer && answer.data && Array.isArray(answer.data.rows)) {
+        answer.data.rows.sort(function (a, b) {
+          return a.id.length < b.id.length ? -1 : (
+            a.id.length > b.id.length ? 1 : 0
+          );
+        });
       }
-    }, "Check document");
-
-    // check attachment
-    deepEqual(util.jsonlocalstorage.getItem(
-      "jio/localstorage/iputatt/iputatt/putattmt1/putattmt2"
-    ), "abc", "Check attachment");
-
-    util.closeAndcleanUpJio(o.jio);
-  });
-
-  test("Get", function () {
+      deepEqual(answer, {
+        "data": {
+          "total_rows": 1,
+          "rows": [{
+            "id": "ce",
+            "value": {"contributor": "DCee"}
+          }]
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List 1 document from 'contributor'");
+    }
 
-    // not sure these need to be run, because the index does not change
-    // and only small modifications have been made to handle putAttachment
-    // tests are from localStorage putAttachment
-    var o = generateTools();
+    function listDocumentsFromIndexTitleYear() {
+      return jio_index.allDocs({"select_list": ["year", "title"]});
+    }
 
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["author"]},
-        {"id": "B", "index": ["year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "iget",
-        "application_name": "iget"
+    function listDocumentsFromIndexTitleYearTest(answer) {
+      if (answer && answer.data && Array.isArray(answer.data.rows)) {
+        answer.data.rows.sort(function (a, b) {
+          return a.id.length < b.id.length ? -1 : (
+            a.id.length > b.id.length ? 1 : 0
+          );
+        });
       }
-    });
-
-    // get inexistent document
-    o.spy(o, "status", 404, "Get inexistent document");
-    o.jio.get({"_id": "get1"}, o.f);
-    o.tick(o);
-
-    // get inexistent attachment
-    o.spy(o, "status", 404, "Get inexistent attachment");
-    o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
-    o.tick(o);
-
-    // adding a document
-    o.doc_get1 = {
-      "_id": "get1",
-      "title": "myGet1"
-    };
-    util.jsonlocalstorage.setItem(
-      "jio/localstorage/iget/iget/get1",
-      o.doc_get1
-    );
-
-    // get document
-    o.spy(o, "value", o.doc_get1, "Get document");
-    o.jio.get({"_id": "get1"}, o.f);
-    o.tick(o);
+      deepEqual(answer, {
+        "data": {
+          "total_rows": 2,
+          "rows": [{
+            "id": "b",
+            "value": {"title": "Bee", "year": 2013}
+          }, {
+            "id": shared.created_document_id,
+            "value": {"title": "Unique ID"}
+          }]
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List 2 documents from 'year' and 'title'");
+    }
 
-    // get inexistent attachment (document exists)
-    o.spy(o, "status", 404, "Get inexistent attachment (document exists)");
-    o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
-    o.tick(o);
+    function listDocumentsFromIndexTitle() {
+      return jio_index.allDocs({"select_list": ["title"]});
+    }
 
-    // adding an attachment
-    o.doc_get1._attachments = {
-      "get2": {
-        "length": 2,
-        // md5("de")
-        "digest": "md5-5f02f0889301fd7be1ac972c11bf3e7d"
+    function listDocumentsFromIndexTitleTest(answer) {
+      if (answer && answer.data && Array.isArray(answer.data.rows)) {
+        answer.data.rows.sort(function (a, b) {
+          return a.id.length < b.id.length ? -1 : (
+            a.id.length > b.id.length ? 1 : 0
+          );
+        });
       }
-    };
-    util.jsonlocalstorage.setItem(
-      "jio/localstorage/iget/iget/get1",
-      o.doc_get1
-    );
-    util.jsonlocalstorage.setItem("jio/localstorage/iget/iget/get1/get2", "de");
-
-    // get attachment
-    o.spy(o, "value", "de", "Get attachment");
-    o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
-    o.tick(o);
-
-    util.closeAndcleanUpJio(o.jio);
-  });
-
-  test("Remove", function () {
-
-    // not sure these need to be run, because the index does not change
-    // and only small modifications have been made to handle putAttachment
-    // tests are from localStorage putAttachment
-    var o = generateTools();
+      deepEqual(answer, {
+        "data": {
+          "total_rows": 2,
+          "rows": [{
+            "id": "b",
+            "value": {"title": "Bee"}
+          }, {
+            "id": shared.created_document_id,
+            "value": {"title": "Unique ID"}
+          }]
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List 2 documents from 'title'");
+    }
 
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["author"]},
-        {"id": "B", "index": ["year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "irem",
-        "application_name": "irem"
-      }
-    });
+    function listDocumentsFromIndexAuthor() {
+      return jio_index.allDocs({"select_list": ["author"]});
+    }
 
-    o.getAttachmentCallback = function (err, response) {
-      if (response) {
-        try {
-          response = JSON.parse(response);
-        } catch (e) {
-          response = "PARSE ERROR " + response;
-        }
+    function listDocumentsFromIndexAuthorTest(answer) {
+      if (answer && answer.data && Array.isArray(answer.data.rows)) {
+        answer.data.rows.sort(function (a, b) {
+          return a.id.length < b.id.length ? -1 : (
+            a.id.length > b.id.length ? 1 : 0
+          );
+        });
       }
-      o.f(err, response);
-    };
-
-    // remove inexistent document
-    o.spy(o, "status", 404, "Remove inexistent document");
-    o.jio.remove({"_id": "remove1"}, o.f);
-    o.tick(o);
-
-    // remove inexistent document/attachment
-    o.spy(o, "status", 404, "Remove inexistent attachment");
-    o.jio.removeAttachment({"_id": "remove1", "_attachment": "remove2"}, o.f);
-    o.tick(o);
-
-    // adding a document
-    o.jio.put({"_id": "remove1", "title": "myRemove1",
-               "author": "Mr. President", "year": "2525"
-              });
-    o.tick(o);
-
-    // adding a 2nd document with same keywords
-    o.jio.put({"_id": "removeAlso", "title": "myRemove2",
-               "author": "Martin Mustermann", "year": "2525"
-              });
-    o.tick(o);
-
-    // remove document
-    o.spy(o, "value", {"ok": true, "id": "remove1"}, "Remove document");
-    o.jio.remove({"_id": "remove1"}, o.f);
-    o.tick(o);
-
-    // check index
-    o.fakeIndexA = {
-      "indexing": ["author"],
-      "free": [0],
-      "location": {
-        "removeAlso": 1
-      },
-      "database": [null, {"_id": "removeAlso", "author": "Martin Mustermann"}]
-    };
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.fakeIndexB = {
-      "indexing": ["year"],
-      "free": [0],
-      "location": {
-        "removeAlso": 1
-      },
-      "database": [null, {"_id": "removeAlso", "year": "2525"}]
-    };
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // check document
-    o.spy(o, "status", 404, "Check if document has been removed");
-    o.jio.get({"_id": "remove1"}, o.f);
-    o.tick(o);
-
-    // adding a new document
-    o.jio.put({"_id": "remove3",
-               "title": "myRemove1",
-               "author": "Mrs Sunshine",
-               "year": "1234"
-              });
-    o.tick(o);
-
-    // adding an attachment
-    o.jio.putAttachment({
-      "_id": "remove3",
-      "_attachment": "removeAtt",
-      "_mimetype": "text/plain",
-      "_data": "hello"
-    });
-    o.tick(o);
-
-    // add another attachment
-    o.jio.putAttachment({
-      "_id": "remove3",
-      "_attachment": "removeAtt2",
-      "_mimetype": "text/plain",
-      "_data": "hello2"
-    });
-    o.tick(o);
-
-    // remove attachment
-    o.spy(o, "value", {"ok": true, "id": "remove3", "attachment": "removeAtt2"},
-          "Remove one of multiple attachment");
-    o.jio.removeAttachment({
-      "_id": "remove3",
-      "_attachment": "removeAtt2"
-    }, o.f);
-    o.tick(o);
-
-    // check index
-    o.fakeIndexA.free = [];
-    o.fakeIndexA.location.remove3 = 0;
-    o.fakeIndexA.database[0] = {"_id": "remove3", "author": "Mrs Sunshine"};
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.fakeIndexB.free = [];
-    o.fakeIndexB.location.remove3 = 0;
-    o.fakeIndexB.database[0] = {"_id": "remove3", "year": "1234"};
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // remove document and attachment together
-    o.spy(o, "value", {"ok": true, "id": "remove3"},
-          "Remove one document and attachment together");
-    o.jio.remove({"_id": "remove3"}, o.f);
-    o.tick(o);
-
-    // check index
-    o.fakeIndexA.free = [0];
-    delete o.fakeIndexA.location.remove3;
-    o.fakeIndexA.database[0] = null;
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.fakeIndexB.free = [0];
-    delete o.fakeIndexB.location.remove3;
-    o.fakeIndexB.database[0] = null;
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    // check attachment
-    o.spy(o, "status", 404, "Check if attachment has been removed");
-    o.jio.getAttachment({"_id": "remove3", "_attachment": "removeAtt"}, o.f);
-    o.tick(o);
-
-    // check document
-    o.spy(o, "status", 404, "Check if document has been removed");
-    o.jio.get({"_id": "remove3"}, o.f);
-    o.tick(o);
-
-    util.closeAndcleanUpJio(o.jio);
-  });
-
-  test("AllDocs", function () {
-
-    var o = generateTools();
+      deepEqual(answer, {
+        "data": {
+          "total_rows": 0,
+          "rows": []
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List 0 document from 'author'");
+    }
 
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["author"]},
-        {"id": "B", "index": ["year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "iall",
-        "application_name": "iall"
-      }
-    });
+    function listDocumentsFromNothing() {
+      return jio_index.allDocs();
+    }
 
-    o.getAttachmentCallback = function (err, response) {
-      if (response) {
-        try {
-          response = JSON.parse(response);
-        } catch (e) {
-          response = "PARSE ERROR " + response;
-        }
+    function listDocumentsFromNothingTest(answer) {
+      if (answer && answer.data && Array.isArray(answer.data.rows)) {
+        answer.data.rows.sort(function (a, b) {
+          return a.id.length < b.id.length ? -1 : (
+            a.id.length > b.id.length ? 1 : 0
+          );
+        });
       }
-      o.f(err, response);
-    };
-
-    // adding documents
-    o.all1 = { "_id": "dragon.doc",
-               "title": "some title", "author": "Dr. No", "year": "1968"
-             };
-    o.spy(o, "value", {"ok": true, "id": "dragon.doc"}, "Put 1");
-    o.jio.put(o.all1, o.f);
-    o.tick(o);
-    o.all2 = {
-      "_id": "timemachine",
-      "title": "hello world",
-      "author": "Dr. Who",
-      "year": "1968"
-    };
-    o.spy(o, "value", {"ok": true, "id": "timemachine"}, "Put 2");
-    o.jio.put(o.all2, o.f);
-    o.tick(o);
-    o.all3 = {
-      "_id": "rocket.ppt",
-      "title": "sunshine.",
-      "author": "Dr. Snuggles",
-      "year": "1985"
-    };
-    o.spy(o, "value", {"ok": true, "id": "rocket.ppt"}, "Put 3");
-    o.jio.put(o.all3, o.f);
-    o.tick(o);
-    o.all4 = {
-      "_id": "stick.jpg",
-      "title": "clouds",
-      "author": "Dr. House",
-      "year": "2005"
-    };
-    o.spy(o, "value", {"ok": true, "id": "stick.jpg"}, "Put 4");
-    o.jio.put(o.all4, o.f);
-    o.tick(o);
-
-    // check index
-    o.fakeIndexA = {
-      "indexing": ["author"],
-      "free": [],
-      "location": {
-        "dragon.doc": 0,
-        "timemachine": 1,
-        "rocket.ppt": 2,
-        "stick.jpg": 3
-      },
-      "database": [
-        {"_id": "dragon.doc", "author": "Dr. No"},
-        {"_id": "timemachine", "author": "Dr. Who"},
-        {"_id": "rocket.ppt", "author": "Dr. Snuggles"},
-        {"_id": "stick.jpg", "author": "Dr. House"}
-      ]
-    };
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
-
-    o.thisShouldBeTheAnswer = {
-      "rows": [
-        {"id": "dragon.doc", "key": "dragon.doc", "value": {} },
-        {"id": "timemachine", "key": "timemachine", "value": {} },
-        {"id": "rocket.ppt", "key": "rocket.ppt", "value": {} },
-        {"id": "stick.jpg", "key": "stick.jpg", "value": {} }
-      ],
-      "total_rows": 4
-    };
-    o.spy(o, "value", o.thisShouldBeTheAnswer, "allDocs (served by index)");
-    o.jio.allDocs(o.f);
-    o.tick(o);
-
-    util.closeAndcleanUpJio(o.jio);
-  });
-
-  test("AllDocs Complex Queries", function () {
-
-    var o = generateTools(), i, m = 15;
+      deepEqual(answer, {
+        "data": {
+          "total_rows": 1,
+          "rows": [{
+            "id": "ce",
+            "value": {}
+          }]
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List 1 document from first index (`allDocs()`)");
+    }
 
-    o.jio = jIO.newJio({
-      "type": "indexed",
-      "indices": [
-        {"id": "A", "index": ["director"]},
-        {"id": "B", "index": ["title", "year"]}
-      ],
-      "sub_storage": {
-        "type": "local",
-        "username": "icomplex",
-        "application_name": "acomplex"
-      }
-    });
-    o.localpath = "jio/localstorage/icomplex/acomplex";
+    function listDocumentsFromLocal() {
+      return jio_local.allDocs();
+    }
 
-    o.getAttachmentCallback = function (err, response) {
-      if (response) {
-        try {
-          response = JSON.parse(response);
-        } catch (e) {
-          response = "PARSE ERROR " + response;
-        }
+    function listDocumentsFromLocalTest(answer) {
+      if (answer && answer.data && Array.isArray(answer.data.rows)) {
+        answer.data.rows.sort(function (a, b) {
+          return a.id.length < b.id.length ? -1 : (
+            a.id.length > b.id.length ? 1 : (
+              a.id < b.id ? -1 : a.id > b.id ? 1 : 0
+            )
+          );
+        });
       }
-      o.f(err, response);
-    };
-
-    // sample data
-    o.titles = [
-      "Shawshank Redemption",
-      "Godfather",
-      "Godfather 2",
-      "Pulp Fiction",
-      "The Good, The Bad and The Ugly",
-      "12 Angry Men",
-      "The Dark Knight",
-      "Schindlers List",
-      "Lord of the Rings - Return of the King",
-      "Fight Club",
-      "Star Wars Episode V",
-      "Lord Of the Rings - Fellowship of the Ring",
-      "One flew over the Cuckoo's Nest",
-      "Inception", "Godfellas"
-    ];
-    o.years = [
-      1994,
-      1972,
-      1974,
-      1994,
-      1966,
-      1957,
-      2008,
-      1993,
-      2003,
-      1999,
-      1980,
-      2001,
-      1975,
-      2010,
-      1990
-    ];
-    o.director = [
-      "Frank Darabont",
-      "Francis Ford Coppola",
-      "Francis Ford Coppola",
-      "Quentin Tarantino",
-      "Sergio Leone",
-      "Sidney Lumet",
-      "Christopher Nolan",
-      "Steven Spielberg",
-      "Peter Jackson",
-      "David Fincher",
-      "Irvin Kershner",
-      "Peter Jackson",
-      "Milos Forman",
-      "Christopher Nolan",
-      " Martin Scorsese"
-    ];
-
-    o.fakeIndexA = {
-      "indexing": ["director"],
-      "free": [],
-      "location": {},
-      "database": []
-    };
-
-    o.fakeIndexB = {
-      "indexing": ["title", "year"],
-      "free": [],
-      "location": {},
-      "database": []
-    };
-
-    for (i = 0; i < m; i += 1) {
-      o.jio.put({
-        "_id": i.toString(),
-        "director": o.director[i],
-        "year": o.years[i],
-        "title": o.titles[i]
-      });
-
-      o.tmp = o.fakeIndexA.free.pop() || o.fakeIndexA.database.length;
-      o.fakeIndexA.database[o.tmp] = {
-        "_id": i.toString(),
-        "director": o.director[i]
-      };
-      o.fakeIndexA.location[i] = o.tmp;
-
-      o.tmp = o.fakeIndexB.free.pop() || o.fakeIndexB.database.length;
-      o.fakeIndexB.database[o.tmp] = {
-        "_id": i.toString(),
-        "year": o.years[i],
-        "title": o.titles[i]
-      };
-      o.fakeIndexB.location[i] = o.tmp;
-
-      o.clock.tick(1000);
+      deepEqual(answer, {
+        "data": {
+          "total_rows": 8,
+          "rows": [{
+            "id": "A",
+            "key": "A",
+            "value": {}
+          }, {
+            "id": "B",
+            "key": "B",
+            "value": {}
+          }, {
+            "id": "C",
+            "key": "C",
+            "value": {}
+          }, {
+            "id": "D",
+            "key": "D",
+            "value": {}
+          }, {
+            "id": "b",
+            "key": "b",
+            "value": {}
+          }, {
+            "id": "ce",
+            "key": "ce",
+            "value": {}
+          }, {
+            "id": "dee",
+            "key": "dee",
+            "value": {}
+          }, {
+            "id": shared.created_document_id,
+            "key": shared.created_document_id,
+            "value": {}
+          }]
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List 8 documents from local (4 document + 4 databases)");
     }
-    // o.clock.tick(1000);
-
-    // check index file
-    o.spy(o, "value", o.fakeIndexA, "Check index file");
-    o.jio.getAttachment({
-      "_id": "A",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
 
-    o.spy(o, "value", o.fakeIndexB, "Check index file");
-    o.jio.getAttachment({
-      "_id": "B",
-      "_attachment": "body"
-    }, o.getAttachmentCallback);
-    o.tick(o);
+    // function removeCreatedDocuments() {
+    //   return success(RSVP.all([
+    //     jio_index.remove({"_id": shared.created_document_id}),
+    //     jio_index.remove({"_id": "b"}),
+    //     jio_index.remove({"_id": "ce"}),
+    //     jio_index.remove({"_id": "dee"})
+    //   ]));
+    // }
+
+    // function removeCreatedDocumentsTest(answers) {
+    //   deepEqual(answers[0], {
+    //     "id": shared.created_document_id,
+    //     "method": "remove",
+    //     "result": "success",
+    //     "status": 204,
+    //     "statusText": "No Content"
+    //   }, "Remove first document");
+
+    //   deepEqual(answers[1], {
+    //     "id": "b",
+    //     "method": "remove",
+    //     "result": "success",
+    //     "status": 204,
+    //     "statusText": "No Content"
+    //   }, "Remove document 'b'");
+
+    //   deepEqual(answers[2], {
+    //     "id": "ce",
+    //     "method": "remove",
+    //     "result": "success",
+    //     "status": 204,
+    //     "statusText": "No Content"
+    //   }, "Remove document 'ce'");
+
+    //   deepEqual(answers[3], {
+    //     "id": "dee",
+    //     "method": "remove",
+    //     "result": "success",
+    //     "status": 204,
+    //     "statusText": "No Content"
+    //   }, "Remove document 'dee'");
+    // }
+
+    // XXX the 2 following functions should be replaced by the 2 commented
+    // previous ones (which don't work yet)
+    function removeCreatedDocuments() {
+      return sequence([function () {
+        return jio_index.remove({"_id": shared.created_document_id});
+      }, function () {
+        return jio_index.remove({"_id": "b"});
+      }, function () {
+        return jio_index.remove({"_id": "ce"});
+      }, function () {
+        return jio_index.remove({"_id": "dee"});
+      }]);
+    }
 
-    // response
-    o.allDocsResponse = {};
-    o.allDocsResponse.rows = [];
-    o.allDocsResponse.total_rows = m;
-    for (i = 0; i < m; i += 1) {
-      o.allDocsResponse.rows.push({
-        "id": i.toString(),
-        "key": i.toString(),
-        "value": {},
-        "doc": {
-          "_id": i.toString(),
-          "title": o.titles[i],
-          "year": o.years[i],
-          "director": o.director[i]
-        }
-      });
+    function removeCreatedDocumentsTest(last_answer) {
+      deepEqual(last_answer, {
+        "id": "dee",
+        "method": "remove",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Remove first document, 'b', 'ce' and 'dee' (testing 'dee' only)");
     }
 
-    o.response = JSON.parse(JSON.stringify(o.allDocsResponse));
-    for (i = 0; i < o.response.rows.length; i += 1) {
-      delete o.response.rows[i].doc;
+    function listEmptyIndexes() {
+      return RSVP.all([
+        success(jio_index.allDocs({"select_list": ["contributor"]})),
+        success(jio_index.allDocs({"select_list": ["title"]})),
+        success(jio_index.allDocs({"select_list": ["title", "year"]})),
+        success(jio_index.allDocs({"select_list": ["author"]})),
+        success(jio_index.allDocs())
+      ]);
     }
 
-    // alldocs
-    o.spy(o, "value", o.response, "AllDocs response generated from index");
-    o.jio.allDocs(o.f);
-    o.tick(o, 1000);
+    function listEmptyIndexesTest(answers) {
+      deepEqual(answers[0], {
+        "data": {
+          "total_rows": 7000,
+          "rows": []
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 200,
+        "statusText": "Ok"
+      }, "List empty indexes 'contributor'");
+
+      deepEqual(answers[1], {
+        "data": {
+          "total_rows": 7000,
+          "rows": []
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "List empty indexes 'title'");
+
+      deepEqual(answers[2], {
+        "data": {
+          "total_rows": 7000,
+          "rows": []
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "List empty indexes 'title', 'year'");
+
+      deepEqual(answers[3], {
+        "data": {
+          "total_rows": 7000,
+          "rows": []
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "List empty indexes 'author'");
+
+      deepEqual(answers[4], {
+        "data": {
+          "total_rows": 7000,
+          "rows": []
+        },
+        "method": "allDocs",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "List default empty indexes");
+    }
 
-    // complex queries
-    o.response = JSON.parse(JSON.stringify(o.allDocsResponse));
-    i = 0;
-    while (i < o.response.rows.length) {
-      if (o.response.rows[i].year < 1980) {
-        o.response.rows.splice(i, 1);
+    // // XXX the 2 following functions should be replaced by the 2 commented
+    // // previous ones (which don't work yet)
+    // function removeCreatedDocuments() {
+    //   return sequence([function () {
+    //     return jio_index.remove({"_id": shared.created_document_id});
+    //   }, function () {
+    //     return jio_index.remove({"_id": "b"});
+    //   }, function () {
+    //     return jio_index.remove({"_id": "ce"});
+    //   }, function () {
+    //     return jio_index.remove({"_id": "dee"});
+    //   }]);
+    // }
+
+    // function removeCreatedDocumentsTest(last_answer) {
+    //   deepEqual(last_answer, {
+    //     "id": "dee",
+    //     "method": "remove",
+    //     "result": "success",
+    //     "status": 204,
+    //     "statusText": "No Content"
+    //   }, "Remove first document, 'b', 'ce' and 'dee' (testing 'dee' only)");
+    // }
+
+    function unexpectedError(error) {
+      if (error instanceof Error) {
+        deepEqual([
+          error.name + ": " + error.message,
+          error
+        ], "UNEXPECTED ERROR", "Unexpected error");
       } else {
-        o.response.rows[i].value = {
-          "year": o.response.rows[i].doc.year,
-          "title": o.response.rows[i].doc.title
-        };
-        delete o.response.rows[i].doc;
-        i += 1;
+        deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
       }
     }
-    o.response.rows.sort(function (a, b) {
-      return (a.value.year > b.value.year ? -1 :
-              a.value.year < b.value.year ? 1 : 0);
-    });
-    o.response.rows.length = 5;
-    o.response.total_rows = 5;
-    o.spy(o, "value", o.response,
-          "allDocs (complex queries year >= 1980, index used to do query)");
-    o.jio.allDocs({
-      // "query":'(year: >= "1980" AND year: < "2000")',
-      "query": '(year: >= "1980")',
-      "limit": [0, 5],
-      "sort_on": [['year', 'descending']],
-      "select_list": ['title', 'year']
-    }, o.f);
-    o.tick(o);
-
-    // complex queries
-    o.spy(o, "value", {"total_rows": 0, "rows": []},
-          "allDocs (complex queries year >= 1980, can't use index)");
-    o.jio.allDocs({
-      // "query":'(year: >= "1980" AND year: < "2000")',
-      "query": '(year: >= "1980")',
-      "limit": [0, 5],
-      "sort_on": [['year', 'descending']],
-      "select_list": ['director', 'year']
-    }, o.f);
-    o.tick(o);
 
-    // empty query returns all
-    o.response = JSON.parse(JSON.stringify(o.allDocsResponse));
-    i = 0;
-    while (i < o.response.rows.length) {
-      o.response.rows[i].value.title =
-        o.response.rows[i].doc.title;
-      delete o.response.rows[i].doc;
-      i += 1;
-    }
-    o.response.rows.sort(function (a, b) {
-      return (a.value.title > b.value.title ? -1 :
-              a.value.title < b.value.title ? 1 : 0);
-    });
-    o.spy(o, "value", o.response,
-          "allDocs (empty query in complex query)");
-    o.jio.allDocs({
-      "sort_on": [['title', 'descending']],
-      "select_list": ['title']
-    }, o.f);
-    o.tick(o);
+    stop();
+
+    // # Post new documents, list them and remove them
+    // post a 201
+    postNewDocument().then(postNewDocumentTest).
+      // get 200
+      then(getCreatedDocument).then(getCreatedDocumentTest).
+      // post b ce dee 201
+      then(postSpecificDocuments).then(postSpecificDocumentsTest).
+      // allD 200 1 documents from index contributor
+      then(listDocumentsFromIndexContributor).
+      then(listDocumentsFromIndexContributorTest).
+      // allD 200 2 documents from index title
+      then(listDocumentsFromIndexTitle).
+      then(listDocumentsFromIndexTitleTest).
+      // allD 200 2 documents from index title year
+      then(listDocumentsFromIndexTitleYear).
+      then(listDocumentsFromIndexTitleYearTest).
+      // allD 200 0 documents from index author
+      then(listDocumentsFromIndexAuthor).
+      then(listDocumentsFromIndexAuthorTest).
+      // allD 200 0 documents from nothing (no select_list option)
+      then(listDocumentsFromNothing).
+      then(listDocumentsFromNothingTest).
+      // allD 200 8 documents from local
+      then(listDocumentsFromLocal).then(listDocumentsFromLocalTest).
+      // remove a b ce dee 204
+      then(removeCreatedDocuments).then(removeCreatedDocumentsTest).
+      // allD 200 empty indexes
+      then(listEmptyIndexes).then(listEmptyIndexesTest).
+
+      // // # Create and update documents, and some attachment and remove them
+      // // put 201
+      // then(putNewDocument).then(putNewDocumentTest).
+      // // get 200
+      // then(getCreatedDocument2).then(getCreatedDocument2Test).
+      // // post 409
+      // then(postSameDocument).then(postSameDocumentTest).
+      // // putA a 204
+      // then(createAttachment).then(createAttachmentTest).
+      // // putA a 204
+      // then(updateAttachment).then(updateAttachmentTest).
+      // // putA b 204
+      // then(createAnotherAttachment).then(createAnotherAttachmentTest).
+      // // put 204
+      // then(updateLastDocument).then(updateLastDocumentTest).
+      // // getA a 200
+      // then(getFirstAttachment).then(getFirstAttachmentTest).
+      // // getA b 200
+      // then(getSecondAttachment).then(getSecondAttachmentTest).
+      // // get 200
+      // then(getLastDocument).then(getLastDocumentTest).
+      // // removeA b 204
+      // then(removeSecondAttachment).then(removeSecondAttachmentTest).
+      // // getA b 404
+      // then(getInexistentSecondAttachment).
+      // then(getInexistentSecondAttachmentTest).
+      // // get 200
+      // then(getOneAttachmentDocument).then(getOneAttachmentDocumentTest).
+      // // removeA b 404
+      //then(removeSecondAttachmentAgain).then(removeSecondAttachmentAgainTest).
+      // // remove 204
+      // then(removeDocument).then(removeDocumentTest).
+      // // getA a 404
+      //then(getInexistentFirstAttachment)
+      //.then(getInexistentFirstAttachmentTest).
+      // // get 404
+      // then(getInexistentDocument).then(getInexistentDocumentTest).
+      // // remove 404
+      // then(removeInexistentDocument).then(removeInexistentDocumentTest).
+      // // check 204
+      // //then(checkDocument).done(checkDocumentTest).
+      // //then(checkStorage).done(checkStorageTest).
+      fail(unexpectedError).
+      always(start);
 
-    util.closeAndcleanUpJio(o.jio);
   });
+
 }));