diff --git a/src/jio.storage/s3storage.js b/src/jio.storage/s3storage.js
index 402d949e0302e3778e874ca7366c36acdc859ad5..5acd2740cc20d87a6fe63cc083ff076aa2eecd3f 100644
--- a/src/jio.storage/s3storage.js
+++ b/src/jio.storage/s3storage.js
@@ -604,7 +604,7 @@
       that.XHRwrapper(command, docId, '', 'GET', mime, '', isJIO, false);
     };
 
-    that.getAttachment = function (command,param,option) {      
+    that.getAttachment = function (command,param,option) {
       var docId, attachId, isJIO, mime;
 
       function getTheAttachment(){
@@ -848,7 +848,8 @@
 
       function putDocument() {
         var data, doc;
-        data = JSON.parse(my_document);
+        //data = JSON.parse(my_document);
+        data = my_document;
         doc = priv.updateMeta(data, docId, attachId, "remove", '');
         that.XHRwrapper(command, docId, '', 'PUT', mime, doc,
           false, false, function (reponse) {
@@ -860,18 +861,35 @@
       function getDocument() {
         that.XHRwrapper(command, docId, '', 'GET', mime, '', false, false,
           function (response) {
-            my_document = response;
-            if (JSON.parse(my_document)._attachments[attachId] !== undefined){
-              putDocument();
-            } else {
+            if (response == '404'){
               return command.error(
-                      404,
-                      "missing attachment",
-                      "This Attachment does not exist"
-                    );
+                404,
+                "missing document",
+                "This Document does not exist"
+              );
+            } else {
+              my_document = JSON.parse(response);
+              if (my_document._attachments == undefined){
+                return command.error(
+                  404,
+                  "missing attachment",
+                  "This Document has no attachments"
+                );
+              }
+              else {
+                if (my_document._attachments[attachId] !== undefined){
+                  putDocument();
+                } else {
+                  return command.error(
+                    404,
+                    "missing attachment",
+                    "This Attachment does not exist"
+                  );
+                }
+              }
             }
           }
-          );
+        );
       }
       getDocument();
     };
@@ -882,7 +900,7 @@
      * @param  {object} command The JIO command
     **/
 
-    that.allDocs = function (command) {
+    that.allDocs = function (command, param, options) {
       var my_document, mime;
       my_document = null;
       mime = 'text/plain; charset=UTF-8';
@@ -946,11 +964,6 @@
 
         errCallback = function (err) {
           if (err.status === 404) {
-            //status
-            //statustext "Not Found"
-            //error
-            //reason "reason"
-            //message "did not work"
             err.error = "not_found";
             command.error(err);
           } else {
@@ -960,81 +973,60 @@
 
         i = resultTable.length - 1;
 
-
-
-
+        ///* JONR : what is the replacement for command.getOption ? */
         // if (command.getOption("include_docs") === true) {
-
-        //   for (i; i >= 0; i -= 1) {
-        //     keyId = resultTable[i];
-        //     Signature = that.encodeAuthorization(keyId);
-        //     callURL = 'http://' + priv.server + '.s3.amazonaws.com/' + keyId;
-        //     requestUTC = new Date().toUTCString();
-        //     parse = true;
-
-        //     allDocResponse.rows[i] = {
-        //       "id": priv.fileNameToIds(keyId).join(),
-        //       "key": keyId,
-        //       "value": {}
-        //     };
-        //     checkCounter = i;
-
-        //     $.ajax({
-        //       contentType : '',
-        //       crossdomain : true,
-        //       url : callURL,
-        //       type : 'GET',
-        //       headers : {
-        //         'Authorization' : "AWS"
-        //           + " "
-        //           + priv.AWSIdentifier
-        //           + ":"
-        //           + Signature,
-        //         'x-amz-date' : requestUTC,
-        //         'Content-Type' : 'application/json'
-        //         //'Content-MD5' : ''
-        //         //'Content-Length' : ,
-        //         //'Expect' : ,
-        //         //'x-amz-security-token' : ,
-        //       },
-        //       success : dealCallback(i, countB, allDocResponse),
-        //       error : errCallback(command.error)
-        //     });
-        //     countB += 1;
-        //   }
-        // } 
-        //else {
+        ///*TRISTANC : 
+        //allDocs = function (command, param, options) {
+        //if (options.include_docs) {   
+        if (options.include_docs) { 
+           for (i; i >= 0; i -= 1) {
+             keyId = resultTable[i];
+             Signature = that.encodeAuthorization(keyId);
+             callURL = 'http://' + priv.server + '.s3.amazonaws.com/' + keyId;
+             requestUTC = new Date().toUTCString();
+             parse = true;
+            allDocResponse.rows[i] = {
+               "id": priv.fileNameToIds(keyId).join(),
+               "key": keyId,
+               "value": {}
+             };
+             checkCounter = i;
+            $.ajax({
+               contentType : '',
+               crossdomain : true,
+               url : callURL,
+               type : 'GET',
+               headers : {
+                 'Authorization' : "AWS"
+                   + " "
+                   + priv.AWSIdentifier
+                   + ":"
+                   + Signature,
+                 'x-amz-date' : requestUTC,
+                 'Content-Type' : 'application/json'
+                 //'Content-MD5' : ''
+                 //'Content-Length' : ,
+                 //'Expect' : ,
+                 //'x-amz-security-token' : ,
+               },
+               success : dealCallback(i, countB, allDocResponse),
+               error : errCallback(command.error)
+             });
+             countB += 1;
+           }
+         } 
+        else {
           for (i; i >= 0; i -= 1) {
             keyId = resultTable[i];
             allDocResponse.rows[i] = {
               "id": priv.fileNameToIds(keyId).join(),
+              "key": priv.fileNameToIds(keyId).join(),
               "value": {}
             };
           }
-
-
-      //     allDocResponse = {
-      //   "data": {
-      //     "total_rows": 2,
-      //     "rows": [{
-      //       "id": "lol",
-      //       "value": {}
-      //     }, {
-      //       "id": "b",
-      //       "value": {}
-      //     }]
-      //   },
-      //   "method": "allDocs",
-      //   "result": "success",
-      //   "status": 200,
-      //   "statusText": "Ok"
-      // };
-
-
-      allDocResponse = {"data":allDocResponse};
+          allDocResponse = {"data":allDocResponse};
           command.success(allDocResponse);
-
-        //}
+        }
       }
 
       function getXML() {
diff --git a/src/jio.storage/splitstorage.js b/src/jio.storage/splitstorage.js
new file mode 100644
index 0000000000000000000000000000000000000000..89af669e7568221840280ba940c89be15314388c
--- /dev/null
+++ b/src/jio.storage/splitstorage.js
@@ -0,0 +1,556 @@
+/*
+ * Copyright 2013, Nexedi SA
+ * Released under the LGPL license.
+ * http://www.gnu.org/licenses/lgpl.html
+ */
+
+/*jslint indent:2, maxlen: 80, nomen: true */
+/*global jIO, define, Blob */
+
+/**
+ * Provides a split storage for JIO. This storage splits data
+ * and store them in the sub storages defined on the description.
+ *
+ *     {
+ *       "type": "split",
+ *       "storage_list": [<storage description>, ...]
+ *     }
+ */
+// define([dependencies], module);
+(function (dependencies, module) {
+  "use strict";
+  if (typeof define === 'function' && define.amd) {
+    return define(dependencies, module);
+  }
+  module(jIO);
+}(['jio'], function (jIO) {
+  "use strict";
+
+  /**
+   * Generate a new uuid
+   *
+   * @method generateUuid
+   * @private
+   * @return {String} The new uuid
+   */
+  function generateUuid() {
+    function S4() {
+      /* 65536 */
+      var i, string = Math.floor(
+        Math.random() * 0x10000
+      ).toString(16);
+      for (i = string.length; i < 4; i += 1) {
+        string = '0' + string;
+      }
+      return string;
+    }
+    return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() +
+      S4() + S4();
+  }
+
+
+  /**
+   * Class to merge allDocs responses from several sub storages.
+   *
+   * @class AllDocsResponseMerger
+   * @constructor
+   */
+  function AllDocsResponseMerger() {
+
+    /**
+     * A list of allDocs response.
+     *
+     * @attribute response_list
+     * @type {Array} Contains allDocs responses
+     * @default []
+     */
+    this.response_list = [];
+  }
+  AllDocsResponseMerger.prototype.constructor = AllDocsResponseMerger;
+
+  /**
+   * Add an allDocs response to the response list.
+   *
+   * @method addResponse
+   * @param  {Object} response The allDocs response.
+   * @return {AllDocsResponseMerger} This
+   */
+  AllDocsResponseMerger.prototype.addResponse = function (response) {
+    this.response_list.push(response);
+    return this;
+  };
+
+  /**
+   * Add several allDocs responses to the response list.
+   *
+   * @method addResponseList
+   * @param  {Array} response_list An array of allDocs responses.
+   * @return {AllDocsResponseMerger} This
+   */
+  AllDocsResponseMerger.prototype.addResponseList = function (response_list) {
+    var i;
+    for (i = 0; i < response_list.length; i += 1) {
+      this.response_list.push(response_list[i]);
+    }
+    return this;
+  };
+
+  /**
+   * Merge the response_list to one allDocs response.
+   *
+   * The merger will find rows with the same id in order to merge them, thanks
+   * to the onRowToMerge method. If no row correspond to an id, rows with the
+   * same id will be ignored.
+   *
+   * @method merge
+   * @param  {Object} [option={}] The merge options
+   * @param  {Boolean} [option.include_docs=false] Tell the merger to also
+   *   merge metadata if true.
+   * @return {Object} The merged allDocs response.
+   */
+  AllDocsResponseMerger.prototype.merge = function (option) {
+    var result = [], row, to_merge = [], tmp, i;
+    if (this.response_list.length === 0) {
+      return [];
+    }
+    /*jslint ass: true */
+    while ((row = this.response_list[0].data.rows.shift()) !== undefined) {
+      to_merge[0] = row;
+      for (i = 1; i < this.response_list.length; i += 1) {
+        to_merge[i] = AllDocsResponseMerger.listPopFromRowId(
+          this.response_list[i].data.rows,
+          row.id
+        );
+        if (to_merge[i] === undefined) {
+          break;
+        }
+      }
+      tmp = this.onRowToMerge(to_merge, option || {});
+      if (tmp !== undefined) {
+        result[result.length] = tmp;
+      }
+    }
+    this.response_list = [];
+    return {"total_rows": result.length, "rows": result};
+  };
+
+  /**
+   * This method is called when the merger want to merge several rows with the
+   * same id.
+   *
+   * @method onRowToMerge
+   * @param  {Array} row_list An array of rows.
+   * @param  {Object} [option={}] The merge option.
+   * @param  {Boolean} [option.include_docs=false] Also merge the metadata if
+   *   true
+   * @return {Object} The merged row
+   */
+  AllDocsResponseMerger.prototype.onRowToMerge = function (row_list, option) {
+    var i, k, new_row = {"value": {}}, data = "";
+    option = option || {};
+    for (i = 0; i < row_list.length; i += 1) {
+      new_row.id = row_list[i].id;
+      if (row_list[i].key) {
+        new_row.key = row_list[i].key;
+      }
+      if (option.include_docs) {
+        new_row.doc = new_row.doc || {};
+        for (k in row_list[i].doc) {
+          if (row_list[i].doc.hasOwnProperty(k)) {
+            if (k[0] === "_") {
+              new_row.doc[k] = row_list[i].doc[k];
+            }
+          }
+        }
+        data += row_list[i].doc.data;
+      }
+    }
+    if (option.include_docs) {
+      try {
+        data = JSON.parse(data);
+      } catch (e) { return undefined; }
+      for (k in data) {
+        if (data.hasOwnProperty(k)) {
+          new_row.doc[k] = data[k];
+        }
+      }
+    }
+    return new_row;
+  };
+
+  /**
+   * Search for a specific row and pop it. During the search operation, all
+   * parsed rows are stored on a dictionnary in order to be found instantly
+   * later.
+   *
+   * @method listPopFromRowId
+   * @param  {Array} rows The row list
+   * @param  {String} doc_id The document/row id
+   * @return {Object/undefined} The poped row
+   */
+  AllDocsResponseMerger.listPopFromRowId = function (rows, doc_id) {
+    var row;
+    if (!rows.dict) {
+      rows.dict = {};
+    }
+    if (rows.dict[doc_id]) {
+      row = rows.dict[doc_id];
+      delete rows.dict[doc_id];
+      return row;
+    }
+    /*jslint ass: true*/
+    while ((row = rows.shift()) !== undefined) {
+      if (row.id === doc_id) {
+        return row;
+      }
+      rows.dict[row.id] = row;
+    }
+  };
+
+
+  /**
+   * The split storage class used by JIO.
+   *
+   * A split storage instance is able to i/o on several sub storages with
+   * split documents.
+   *
+   * @class SplitStorage
+   */
+  function SplitStorage(spec) {
+    var that = this, priv = {};
+
+    /**
+     * The list of sub storages we want to use to store part of documents.
+     *
+     * @attribute storage_list
+     * @private
+     * @type {Array} Array of storage descriptions
+     */
+    priv.storage_list = spec.storage_list;
+
+    //////////////////////////////////////////////////////////////////////
+    // Tools
+
+    /**
+     * Send a command to all sub storages. All the response are returned
+     * in a list. The index of the response correspond to the storage_list
+     * index. If an error occurs during operation, the callback is called with
+     * `callback(err, undefined)`. The response is given with
+     * `callback(undefined, response_list)`.
+     *
+     * `doc` is the document informations but can also be a list of dedicated
+     * document informations. In this case, each document is associated to one
+     * sub storage.
+     *
+     * @method send
+     * @private
+     * @param  {String} method The command method
+     * @param  {Object,Array} doc The document information to send to each sub
+     *   storages or a list of dedicated document
+     * @param  {Object} option The command option
+     * @param  {Function} callback Called at the end
+     */
+    priv.send = function (command, method, doc, option, callback) {
+      var i, answer_list = [], failed = false;
+      function onEnd() {
+        i += 1;
+        if (i === priv.storage_list.length) {
+          callback(undefined, answer_list);
+        }
+      }
+      function onSuccess(i) {
+        return function (response) {
+          if (!failed) {
+            answer_list[i] = response;
+          }
+          onEnd();
+        };
+      }
+      function onError(i) {
+        return function (err) {
+          if (!failed) {
+            failed = true;
+            err.index = i;
+            callback(err, undefined);
+          }
+        };
+      }
+      if (!Array.isArray(doc)) {
+        for (i = 0; i < priv.storage_list.length; i += 1) {
+          if (method === 'allDocs') {
+            command.storage(priv.storage_list[i])[method](option).
+              then(onSuccess(i), onError(i));
+          } else {
+            command.storage(priv.storage_list[i])[method](doc, option).
+              then(onSuccess(i), onError(i));
+          }
+        }
+      } else {
+        for (i = 0; i < priv.storage_list.length; i += 1) {
+          // we assume that alldocs is not called if the there is several docs
+          command.storage(priv.storage_list[i])[method](doc[i], option).
+            then(onSuccess(i), onError(i));
+        }
+      }
+      i = 0;
+    };
+
+    /**
+     * Split document metadata then store them to the sub storages.
+     *
+     * @method postOrPut
+     * @private
+     * @param  {Object} doc A serialized document object
+     * @param  {Object} option Command option properties
+     * @param  {String} method The command method ('post' or 'put')
+     */
+    priv.postOrPut = function (command, doc, option, method) {
+      var i, data, doc_list = [], doc_underscores = {};
+      if (!doc._id) {
+        doc._id = generateUuid(); // XXX should let gidstorage guess uid
+      }
+      for (i in doc) {
+        if (doc.hasOwnProperty(i)) {
+          if (i[0] === "_") {
+            doc_underscores[i] = doc[i];
+            delete doc[i];
+          }
+        }
+      }
+      data = JSON.stringify(doc);
+      for (i = 0; i < priv.storage_list.length; i += 1) {
+        doc_list[i] = JSON.parse(JSON.stringify(doc_underscores));
+        doc_list[i].data = data.slice(
+          (data.length / priv.storage_list.length) * i,
+          (data.length / priv.storage_list.length) * (i + 1)
+        );
+      }
+      priv.send(command, method, doc_list, option, function (err) {
+        if (err) {
+          err.message = "Unable to " + method + " document";
+          delete err.index;
+          return command.error(err);
+        }
+        command.success({"id": doc_underscores._id});
+      });
+    };
+
+    //////////////////////////////////////////////////////////////////////
+    // JIO commands
+
+    /**
+     * Split document metadata then store them to the sub storages.
+     *
+     * @method post
+     * @param  {Object} command The JIO command
+     */
+    that.post = function (command, metadata, option) {
+      priv.postOrPut(command, metadata, option, 'post');
+    };
+
+    /**
+     * Split document metadata then store them to the sub storages.
+     *
+     * @method put
+     * @param  {Object} command The JIO command
+     */
+    that.put = function (command, metadata, option) {
+      priv.postOrPut(command, metadata, option, 'put');
+    };
+
+    /**
+     * Puts an attachment to the sub storages.
+     *
+     * @method putAttachment
+     * @param  {Object} command The JIO command
+     */
+    that.putAttachment = function (command, param, option) {
+      var i, attachment_list = [], data = param._blob;
+      for (i = 0; i < priv.storage_list.length; i += 1) {
+        attachment_list[i] = jIO.util.deepClone(param);
+        attachment_list[i]._blob = data.slice(
+          data.size * i / priv.storage_list.length,
+          data.size * (i + 1) / priv.storage_list.length,
+          data.type
+        );
+      }
+      priv.send(
+        command,
+        'putAttachment',
+        attachment_list,
+        option,
+        function (err) {
+          if (err) {
+            err.message = "Unable to put attachment";
+            delete err.index;
+            return command.error(err);
+          }
+          command.success();
+        }
+      );
+    };
+
+    /**
+     * Gets splited document metadata then returns real document.
+     *
+     * @method get
+     * @param  {Object} command The JIO command
+     */
+    that.get = function (command, param, option) {
+      var doc = param;
+      priv.send(command, 'get', doc, option, function (err, response) {
+        var i, k;
+        if (err) {
+          err.message = "Unable to get document";
+          delete err.index;
+          return command.error(err);
+        }
+        doc = '';
+        for (i = 0; i < response.length; i += 1) {
+          response[i] = response[i].data;
+          doc += response[i].data;
+        }
+        doc = JSON.parse(doc);
+        for (i = 0; i < response.length; i += 1) {
+          for (k in response[i]) {
+            if (response[i].hasOwnProperty(k)) {
+              if (k[0] === "_") {
+                doc[k] = response[i][k];
+              }
+            }
+          }
+        }
+        delete doc._attachments;
+        for (i = 0; i < response.length; i += 1) {
+          if (response[i]._attachments) {
+            for (k in response[i]._attachments) {
+              if (response[i]._attachments.hasOwnProperty(k)) {
+                doc._attachments = doc._attachments || {};
+                doc._attachments[k] = doc._attachments[k] || {
+                  "length": 0,
+                  "content_type": ""
+                };
+                doc._attachments[k].length += response[i]._attachments[k].
+                  length;
+                // if (response[i]._attachments[k].digest) {
+                //   if (doc._attachments[k].digest) {
+                //     doc._attachments[k].digest += " " + response[i].
+                //       _attachments[k].digest;
+                //   } else {
+                //     doc._attachments[k].digest = response[i].
+                //       _attachments[k].digest;
+                //   }
+                // }
+                doc._attachments[k].content_type = response[i]._attachments[k].
+                  content_type;
+              }
+            }
+          }
+        }
+        command.success({"data": doc});
+      });
+    };
+
+    /**
+     * Gets splited document attachment then returns real attachment data.
+     *
+     * @method getAttachment
+     * @param  {Object} command The JIO command
+     */
+    that.getAttachment = function (command, param, option) {
+      priv.send(command, 'getAttachment', param, option, function (
+        err,
+        response
+      ) {
+        if (err) {
+          err.message = "Unable to get attachment";
+          delete err.index;
+          return command.error(err);
+        }
+
+        command.success({"data": new Blob(response.map(function (answer) {
+          return answer.data;
+        }), {"type": response[0].data.type})});
+      });
+    };
+
+    /**
+     * Removes a document from the sub storages.
+     *
+     * @method remove
+     * @param  {Object} command The JIO command
+     */
+    that.remove = function (command, param, option) {
+      priv.send(
+        command,
+        'remove',
+        param,
+        option,
+        function (err) {
+          if (err) {
+            err.message = "Unable to remove document";
+            delete err.index;
+            return command.error(err);
+          }
+          command.success();
+        }
+      );
+    };
+
+    /**
+     * Removes an attachment from the sub storages.
+     *
+     * @method removeAttachment
+     * @param  {Object} command The JIO command
+     */
+    that.removeAttachment = function (command, param, option) {
+      priv.send(
+        command,
+        'removeAttachment',
+        param,
+        option,
+        function (err) {
+          if (err) {
+            err.message = "Unable to remove attachment";
+            delete err.index;
+            return command.error(err);
+          }
+          command.success();
+        }
+      );
+    };
+
+    /**
+     * Retreive a list of all document in the sub storages.
+     *
+     * If include_docs option is false, then it returns the document list from
+     * the first sub storage. Else, it will merge results and return.
+     *
+     * @method allDocs
+     * @param  {Object} command The JIO command
+     */
+    that.allDocs = function (command, param, option) {
+      option = {"include_docs": option.include_docs};
+      priv.send(
+        command,
+        'allDocs',
+        param,
+        option,
+        function (err, response_list) {
+          var all_docs_merger;
+          if (err) {
+            err.message = "Unable to retrieve document list";
+            delete err.index;
+            return command.error(err);
+          }
+          all_docs_merger = new AllDocsResponseMerger();
+          all_docs_merger.addResponseList(response_list);
+          return command.success({"data": all_docs_merger.merge(option)});
+        }
+      );
+    };
+
+  } // end of splitStorage
+
+  jIO.addStorage('split', SplitStorage);
+}));
diff --git a/src/jio.storage/splitstorage.tests.js b/src/jio.storage/splitstorage.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..e1d1f481501137b58276a716f3a64c411e9c871a
--- /dev/null
+++ b/src/jio.storage/splitstorage.tests.js
@@ -0,0 +1,964 @@
+/*jslint indent: 2, maxlen: 80, nomen: true */
+/*global define, jIO, test_util, RSVP, test, ok, deepEqual, module, stop,
+  start, hex_sha256 */
+
+// define([module_name], [dependencies], module);
+(function (dependencies, module) {
+  "use strict";
+  if (typeof define === 'function' && define.amd) {
+    return define(dependencies, module);
+  }
+  module(jIO, test_util, RSVP);
+}([
+  'jio',
+  'test_util',
+  'rsvp',
+  'localstorage',
+  'splitstorage'
+], function (jIO, util, RSVP) {
+  "use strict";
+
+  var tool = {
+    "readBlobAsBinaryString": jIO.util.readBlobAsBinaryString
+  };
+
+  function reverse(promise) {
+    return new RSVP.Promise(function (resolve, reject, notify) {
+      promise.then(reject, resolve, notify);
+    }, function () {
+      promise.cancel();
+    });
+  }
+
+  /**
+   * sequence(thens): Promise
+   *
+   * Executes a sequence of *then* callbacks. It acts like
+   * `smth().then(callback).then(callback)...`. The first callback is called
+   * with no parameter.
+   *
+   * Elements of `thens` array can be a function or an array contaning at most
+   * three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
+   *
+   * When `cancel()` is executed, each then promises are cancelled at the same
+   * time.
+   *
+   * @param  {Array} thens An array of *then* callbacks
+   * @return {Promise} A new promise
+   */
+  function sequence(thens) {
+    var promises = [];
+    return new RSVP.Promise(function (resolve, reject, notify) {
+      var i;
+      promises[0] = new RSVP.Promise(function (resolve) {
+        resolve();
+      });
+      for (i = 0; i < thens.length; i += 1) {
+        if (Array.isArray(thens[i])) {
+          promises[i + 1] = promises[i].
+            then(thens[i][0], thens[i][1], thens[i][2]);
+        } else {
+          promises[i + 1] = promises[i].then(thens[i]);
+        }
+      }
+      promises[i].then(resolve, reject, notify);
+    }, function () {
+      var i;
+      for (i = 0; i < promises.length; i += 1) {
+        promises[i].cancel();
+      }
+    });
+  }
+
+  function unexpectedError(error) {
+    if (error instanceof Error) {
+      deepEqual([
+        error.name + ": " + error.message,
+        error
+      ], "UNEXPECTED ERROR", "Unexpected error");
+    } else {
+      deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
+    }
+  }
+
+  module("SplitStorage + LocalStorage");
+
+  test("Post", function () {
+    var shared = {}, jio, jio_local_list = [];
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "post1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "post2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+    jio_local_list[0] = jIO.createJIO(shared.local_storage_description1, {
+      "workspace": shared.workspace
+    });
+    jio_local_list[1] = jIO.createJIO(shared.local_storage_description2, {
+      "workspace": shared.workspace
+    });
+    jio_local_list.run = function (method, argument) {
+      var i, promises = [];
+      for (i = 0; i < this.length; i += 1) {
+        promises[i] = this[i][method].apply(this[i], argument);
+      }
+      return RSVP.all(promises);
+    };
+    jio_local_list.get = function () {
+      return this.run("get", arguments);
+    };
+
+    stop();
+    // post without id
+    jio.post({
+      "_underscored_meta": "uvalue",
+      "meta": "data"
+    }).then(function (answer) {
+      shared.uuid = answer.id;
+      answer.id = "<uuid>";
+      ok(util.isUuid(shared.uuid), "Uuid should look like " +
+         "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + shared.uuid);
+      deepEqual(answer, {
+        "id": "<uuid>",
+        "method": "post",
+        "result": "success",
+        "status": 201,
+        "statusText": "Created"
+      }, "Post document without id");
+
+      // check uploaded documents
+      return jio_local_list.get({"_id": shared.uuid});
+
+    }).then(function (answers) {
+      var i;
+      for (i = 0; i < answers.length; i += 1) {
+        deepEqual(answers[i].data, {
+          "_id": shared.uuid,
+          "_underscored_meta": "uvalue",
+          "data": i === 0 ? "{\"meta\"" : ":\"data\"}"
+        }, "Check uploaded document in sub storage " + (i + 1));
+      }
+
+      // post with id
+      return jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data",
+        "hello": "world"
+      });
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "one",
+        "method": "post",
+        "result": "success",
+        "status": 201,
+        "statusText": "Created"
+      }, "Post document with id");
+
+      // check uploaded documents
+      return jio_local_list.get({"_id": "one"});
+
+    }).then(function (answers) {
+
+      deepEqual(answers[0].data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "data": "{\"meta\":\"data\","
+      }, "Check uploaded document in sub storage 1");
+
+      deepEqual(answers[1].data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "data": "\"hello\":\"world\"}"
+      }, "Check uploaded document in sub storage 2");
+
+      // post with id
+      return reverse(jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data",
+        "hello": "world"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "conflict",
+        "id": "one",
+        "message": "Unable to post document",
+        "method": "post",
+        "reason": "document exists",
+        "result": "error",
+        "status": 409,
+        "statusText": "Conflict"
+      }, "Post document with same id -> 409 Conflict");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("PutAttachment", function () {
+    var shared = {}, jio, jio_local_list = [];
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "putAttachment1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "putAttachment2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+    jio_local_list[0] = jIO.createJIO(shared.local_storage_description1, {
+      "workspace": shared.workspace
+    });
+    jio_local_list[1] = jIO.createJIO(shared.local_storage_description2, {
+      "workspace": shared.workspace
+    });
+    jio_local_list.run = function (method, argument) {
+      var i, promises = [];
+      for (i = 0; i < this.length; i += 1) {
+        promises[i] = this[i][method].apply(this[i], argument);
+      }
+      return RSVP.all(promises);
+    };
+    jio_local_list.get = function () {
+      return this.run("get", arguments);
+    };
+    jio_local_list.getAttachmentAsBinaryString = function () {
+      return this.run("getAttachment", arguments).then(function (answers) {
+        var i, promises = [];
+        for (i = 0; i < answers.length; i += 1) {
+          promises[i] = tool.readBlobAsBinaryString(answers[i].data);
+        }
+        return RSVP.all(promises);
+      });
+    };
+
+    stop();
+
+    return reverse(jio.putAttachment({
+      "_id": "one",
+      "_attachment": "my_attachment",
+      "_data": "My Data",
+      "_content_type": "text/plain"
+    })).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to put attachment",
+        "method": "putAttachment",
+        "reason": "missing",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Put attachment on a inexistent document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return jio.putAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "id": "one",
+        "method": "putAttachment",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Put attachment on a document");
+
+      // check uploaded documents
+      return jio_local_list.get({"_id": "one"});
+
+    }).then(function (answers) {
+
+      deepEqual(answers[0].data, {
+        "_attachments": {
+          "my_attachment": {
+            "content_type": "text/plain",
+            "digest": "sha256-ebf2d770a6a2dfa135f6c81431f22fc3cbcde9ae" +
+              "e52759ca9e520d4d964c1322", // sha256("My ")
+            "length": 3
+          }
+        },
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "data": "{\"meta\""
+      }, "Check uploaded document in sub storage 1");
+
+      deepEqual(answers[1].data, {
+        "_attachments": {
+          "my_attachment": {
+            "content_type": "text/plain",
+            "digest": "sha256-cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b" +
+              "3cdf79496dc442d52b8dd528", // sha256("Data")
+            "length": 4
+          }
+        },
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "data": ":\"data\"}"
+      }, "Check uploaded document in sub storage 2");
+
+      return jio_local_list.getAttachmentAsBinaryString({
+        "_id": "one",
+        "_attachment": "my_attachment"
+      });
+
+    }).then(function (events) {
+
+      deepEqual(events[0].target.result, "My ",
+                "Check uploaded document in sub storage 1");
+      deepEqual(events[1].target.result, "Data",
+                "Check uploaded document in sub storage 1");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("Get", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "get1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "get2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.get({"_id": "one"})).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to get document",
+        "method": "get",
+        "reason": "missing",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Get missing document");
+
+      return jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return jio.get({"_id": "one"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      }, "Get posted document");
+
+      return jio.putAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_content_type": "text/plain"
+      });
+
+    }).then(function () {
+
+      return jio.get({"_id": "one"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data",
+        "_attachments": {
+          "my_attachment": {
+            "length": 7,
+            "content_type": "text/plain"
+          }
+        }
+      }, "Get document with attachment informations");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("GetAttachment", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "getAttachment1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "getAttachment2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.getAttachment({
+      "_id": "one",
+      "_attachment": "my_attachment"
+    })).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to get attachment",
+        "method": "getAttachment",
+        "reason": "missing document",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Get attachment from missing document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return reverse(jio.getAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to get attachment",
+        "method": "getAttachment",
+        "reason": "missing attachment",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Get missing attachment from document");
+
+      return jio.putAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    }).then(function () {
+
+      return jio.getAttachment({"_id": "one", "_attachment": "my_attachment"});
+
+    }).then(function (answer) {
+      return tool.readBlobAsBinaryString(answer.data);
+    }).then(function (event) {
+
+      deepEqual(event.target.result, "My Data", "Get attachment");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("RemoveAttachment", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "removeAttachment1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "removeAttachment2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.removeAttachment({
+      "_id": "one",
+      "_attachment": "my_attachment"
+    })).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to remove attachment",
+        "method": "removeAttachment",
+        "reason": "missing document",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Remove attachment from inexistent document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return reverse(jio.removeAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to remove attachment",
+        "method": "removeAttachment",
+        "reason": "missing attachment",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Remove inexistent attachment -> 404 Not Found");
+
+      return jio.putAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    }).then(function () {
+
+      return jio.removeAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment"
+      });
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "id": "one",
+        "method": "removeAttachment",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Remove attachment");
+
+      return jio.get({"_id": "one"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      }, "Check document");
+
+      return reverse(jio.getAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to get attachment",
+        "method": "getAttachment",
+        "reason": "missing attachment",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Check attachment -> 404 Not Found");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("Remove", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "remove1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "remove2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.remove({"_id": "one"})).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to remove document",
+        "method": "remove",
+        "reason": "missing",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Remove missing document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return jio.putAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    }).then(function () {
+
+      return jio.remove({"_id": "one"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "one",
+        "method": "remove",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Remove document");
+
+      return reverse(jio.getAttachment({
+        "_id": "one",
+        "_attachment": "my_attachment"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to get attachment",
+        "method": "getAttachment",
+        "reason": "missing document",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Check attachment -> 404 Not Found");
+
+      return reverse(jio.get({"_id": "one"}));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "not_found",
+        "id": "one",
+        "message": "Unable to get document",
+        "method": "get",
+        "reason": "missing",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Check document -> 404 Not Found");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("Put", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "put1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "put2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    jio.put({
+      "_id": "one",
+      "_underscored_meta": "uvalue",
+      "meta": "data"
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "one",
+        "method": "put",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Put new document");
+
+      return jio.get({"_id": "one"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      }, "Check document");
+
+      return jio.put({
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meow": "dog"
+      });
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "one",
+        "method": "put",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Put same document again");
+
+      return jio.get({"_id": "one"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "one",
+        "_underscored_meta": "uvalue",
+        "meow": "dog"
+      }, "Get document for check");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("AllDocs", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.local_storage_description1 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "alldocs1",
+      "mode": "memory"
+    };
+    shared.local_storage_description2 = {
+      "type": "local",
+      "username": "splitstorage",
+      "application_name": "alldocs2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.local_storage_description1,
+        shared.local_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    function prepareDatabase() {
+      var i, do_list = [];
+      function post(i) {
+        return function () {
+          return jio.post({
+            "_id": "doc" + i,
+            "_underscored_meta": "uvalue" + i,
+            "meta": "data" + i
+          });
+        };
+      }
+      function putAttachment(i) {
+        return function () {
+          return jio.putAttachment({
+            "_id": "doc" + i,
+            "_attachment": "my_attachment" + i,
+            "_data": "My Data" + i,
+            "_content_type": "text/plain"
+          });
+        };
+      }
+      for (i = 0; i < 5; i += 1) {
+        do_list.push(post(i));
+      }
+      for (i = 0; i < 2; i += 1) {
+        do_list.push(putAttachment(i));
+      }
+      return sequence(do_list);
+    }
+
+    prepareDatabase().then(function () {
+
+      return jio.get({"_id": "doc1"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "doc1",
+        "_underscored_meta": "uvalue1",
+        "meta": "data1",
+        "_attachments": {
+          "my_attachment1": {
+            "length": 8,
+            "content_type": "text/plain"
+          }
+        }
+      }, "Check document");
+
+      return jio.allDocs();
+
+    }).then(function (answer) {
+
+      answer.data.rows.sort(function (a, b) {
+        return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
+      });
+
+      deepEqual(answer.data, {
+        "total_rows": 5,
+        "rows": [{
+          "id": "doc0",
+          "key": "doc0",
+          "value": {}
+        }, {
+          "id": "doc1",
+          "key": "doc1",
+          "value": {}
+        }, {
+          "id": "doc2",
+          "key": "doc2",
+          "value": {}
+        }, {
+          "id": "doc3",
+          "key": "doc3",
+          "value": {}
+        }, {
+          "id": "doc4",
+          "key": "doc4",
+          "value": {}
+        }]
+      }, "AllDocs with document ids only");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+}));
diff --git a/src/jio/core/JobQueue.js b/src/jio/core/JobQueue.js
index 451ae57956cba246fd19c755e2f450a1173de52a..6f7328c789ff8362d2b9d8f2f9711bf253ed0592 100644
--- a/src/jio/core/JobQueue.js
+++ b/src/jio/core/JobQueue.js
@@ -98,6 +98,8 @@ JobQueue.prototype.repair = function () {
  * @return {Number} The generated id
  */
 JobQueue.prototype.post = function (job) {
+  console.log('jio core');
+  console.log(job);
   var i, next = 1;
   // get next id
   for (i = 0; i < this._array.length; i += 1) {
diff --git a/test/jio.storage/s3storage.livetests.html b/test/jio.storage/s3storage.livetests.html
index 19469275e7ec8febaf7495e81a1197fc758ade55..07da17a944682d32e65b28a591dfc6921385c1a5 100644
--- a/test/jio.storage/s3storage.livetests.html
+++ b/test/jio.storage/s3storage.livetests.html
@@ -13,6 +13,7 @@
   <script src="../../complex_queries.js"></script>
   <script src="../../src/sha1.amd.js"></script>
   <script src="../../src/jio.storage/s3storage.js"></script>
+  <script src="../../src/jio.storage/splitstorage.js"></script>
   <script src="../jio/util.js"></script>
 </head>
 <body>
@@ -35,6 +36,7 @@ location.href.split('?')[1].split('&').forEach(function (item) {
   </form>
   <br />
   <div id="qunit"></div>
-  <script src="s3storage.tests.js"></script>
+  <!--<script src="s3storage.tests.js"></script>-->
+  <script src="split.s3storage.tests.js"></script>
 </body>
 </html>
diff --git a/test/jio.storage/s3storage.tests.js b/test/jio.storage/s3storage.tests.js
index bafa99a956304b4b319eaabc716b9e28ea3bef30..18163cc50286efb2ad04da5f0da30d817068cc31 100644
--- a/test/jio.storage/s3storage.tests.js
+++ b/test/jio.storage/s3storage.tests.js
@@ -1,6 +1,6 @@
 /*jslint indent: 2, maxlen: 80, nomen: true */
 /*global module, test, stop, start, expect, ok, deepEqual, location, sinon,
-  davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa */
+  davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa, s3storage_spec */
 
 (function () {
   "use strict";
@@ -9,11 +9,6 @@
   if (typeof s3storage_spec === 'object') {
     use_fake_server = false;
     spec = s3storage_spec;
-  } else {
-    spec = dav_storage.createDescription(
-      "http://localhost",
-      "none"
-    );
   }
 
   module("S3 Storage");
@@ -198,35 +193,7 @@
       responses.push([
         200,
         {"Content-Type": "text/xml"},
-        '<?xml version="1.0" encoding="utf-8"?>' +
-          '<D:multistatus xmlns:D="DAV:">' +
-          '<D:response xmlns:lp2="http://apache.org/dav/props/" ' +
-          'xmlns:lp1="DAV:">' +
-          '<D:href>/uploads/</D:href>' +
-          '<D:propstat>' +
-          '<D:prop>' +
-          '<lp1:resourcetype><D:collection/></lp1:resourcetype>' +
-          '<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>' +
-          '<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT' +
-          '</lp1:getlastmodified>' +
-          '<lp1:getetag>"240be-1000-4e6bb3840a9ac"</lp1:getetag>' +
-          '<D:supportedlock>' +
-          '<D:lockentry>' +
-          '<D:lockscope><D:exclusive/></D:lockscope>' +
-          '<D:locktype><D:write/></D:locktype>' +
-          '</D:lockentry>' +
-          '<D:lockentry>' +
-          '<D:lockscope><D:shared/></D:lockscope>' +
-          '<D:locktype><D:write/></D:locktype>' +
-          '</D:lockentry>' +
-          '</D:supportedlock>' +
-          '<D:lockdiscovery/>' +
-          '<D:getcontenttype>httpd/unix-directory</D:getcontenttype>' +
-          '</D:prop>' +
-          '<D:status>HTTP/1.1 200 OK</D:status>' +
-          '</D:propstat>' +
-          '</D:response>' +
-          '</D:multistatus>'
+        ''
       ]); // PROPFIND
       return jio.allDocs();
     }
@@ -899,4 +866,7 @@
 
   });
 
+  module("SplitStorage + S3 Storage");
+
+
 }());
diff --git a/test/jio.storage/split.s3storage.tests.js b/test/jio.storage/split.s3storage.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..47f5995d43761cc30e1453923fa9192239ed0a63
--- /dev/null
+++ b/test/jio.storage/split.s3storage.tests.js
@@ -0,0 +1,967 @@
+/*jslint indent: 2, maxlen: 80, nomen: true */
+/*global define, jIO, test_util, RSVP, test, ok, deepEqual, module, stop,
+  start, hex_sha256 */
+
+// define([module_name], [dependencies], module);
+(function (dependencies, module) {
+  "use strict";
+  if (typeof define === 'function' && define.amd) {
+    return define(dependencies, module);
+  }
+  module(jIO, test_util, RSVP);
+}([
+  'jio',
+  'test_util',
+  'rsvp',
+  's3storage',
+  'splitstorage'
+], function (jIO, util, RSVP) {
+  "use strict";
+
+  var tool = {
+    "readBlobAsBinaryString": jIO.util.readBlobAsBinaryString
+  };
+
+  function reverse(promise) {
+    return new RSVP.Promise(function (resolve, reject, notify) {
+      promise.then(reject, resolve, notify);
+    }, function () {
+      promise.cancel();
+    });
+  }
+
+  /**
+   * sequence(thens): Promise
+   *
+   * Executes a sequence of *then* callbacks. It acts like
+   * `smth().then(callback).then(callback)...`. The first callback is called
+   * with no parameter.
+   *
+   * Elements of `thens` array can be a function or an array contaning at most
+   * three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
+   *
+   * When `cancel()` is executed, each then promises are cancelled at the same
+   * time.
+   *
+   * @param  {Array} thens An array of *then* callbacks
+   * @return {Promise} A new promise
+   */
+  function sequence(thens) {
+    var promises = [];
+    return new RSVP.Promise(function (resolve, reject, notify) {
+      var i;
+      promises[0] = new RSVP.Promise(function (resolve) {
+        resolve();
+      });
+      for (i = 0; i < thens.length; i += 1) {
+        if (Array.isArray(thens[i])) {
+          promises[i + 1] = promises[i].
+            then(thens[i][0], thens[i][1], thens[i][2]);
+        } else {
+          promises[i + 1] = promises[i].then(thens[i]);
+        }
+      }
+      promises[i].then(resolve, reject, notify);
+    }, function () {
+      var i;
+      for (i = 0; i < promises.length; i += 1) {
+        promises[i].cancel();
+      }
+    });
+  }
+
+  function unexpectedError(error) {
+    if (error instanceof Error) {
+      deepEqual([
+        error.name + ": " + error.message,
+        error
+      ], "UNEXPECTED ERROR", "Unexpected error");
+    } else {
+      deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
+    }
+  }
+
+  module("SplitStorage + S3 Storage");
+
+  test("Post", function () {
+    var shared = {}, jio, jio_s3_list = [];
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+    jio_s3_list[0] = jIO.createJIO(shared.s3_storage_description1, {
+      "workspace": shared.workspace
+    });
+    jio_s3_list[1] = jIO.createJIO(shared.s3_storage_description2, {
+      "workspace": shared.workspace
+    });
+    jio_s3_list.run = function (method, argument) {
+      var i, promises = [];
+      for (i = 0; i < this.length; i += 1) {
+        promises[i] = this[i][method].apply(this[i], argument);
+      }
+      return RSVP.all(promises);
+    };
+    jio_s3_list.get = function () {
+      return this.run("get", arguments);
+    };
+
+    stop();
+    // post without id
+    jio.post({
+      "_underscored_meta": "uvalue",
+      "meta": "data"
+    })
+      .then(function (answer) {
+        shared.uuid = answer.id;
+        answer.id = "<uuid>";
+        ok(util.isUuid(shared.uuid), "Uuid should look like " +
+          "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + shared.uuid);
+        deepEqual(answer, {
+          "id": "<uuid>",
+          "method": "post",
+          "result": "success",
+          "status": 201,
+          "statusText": "Created"
+        }, "Post document without id");
+        // check uploaded documents
+        return jio_s3_list.get({"_id": shared.uuid});
+      })
+
+      .then(function (answers) {
+        var i;
+        for (i = 0; i < answers.length; i += 1) {
+          deepEqual(answers[i].data, {
+            "_id": shared.uuid,
+            "_underscored_meta": "uvalue",
+            "data": i === 0 ? "{\"meta\"" : ":\"data\"}"
+          }, "Check uploaded document in sub storage " + (i + 1));
+        }
+        // post with id
+        return jio.post({
+          "_id": "one",
+          "_underscored_meta": "uvalue",
+          "meta": "data",
+          "hello": "world"
+        });
+      })
+      .then(function (answer) {
+        deepEqual(answer, {
+          "id": "one",
+          "method": "post",
+          "result": "success",
+          "status": 201,
+          "statusText": "Created"
+        }, "Post document with id");
+        // check uploaded documents
+        return jio_s3_list.get({"_id": "one"});
+      })
+
+      .then(function (answers) {
+        deepEqual(answers[0].data, {
+          "_id": "one",
+          "_underscored_meta": "uvalue",
+          "data": "{\"meta\":\"data\","
+        }, "Check uploaded document in sub storage 1");
+        deepEqual(answers[1].data, {
+          "_id": "one",
+          "_underscored_meta": "uvalue",
+          "data": "\"hello\":\"world\"}"
+        }, "Check uploaded document in sub storage 2");
+        // post with id
+        return reverse(jio.post({
+          "_id": "one",
+          "_underscored_meta": "uvalue",
+          "meta": "data",
+          "hello": "world"
+        }));
+      })
+      .then(function (answer) {
+        deepEqual(answer, {
+          "error": "conflict",
+          "id": "one",
+          "message": "Unable to post document",
+          "method": "post",
+          "reason": "Document already exists",
+          "result": "error",
+          "status": 409,
+          "statusText": "Conflict"
+        }, "Post document with same id -> 409 Conflict");
+      })
+      .fail(unexpectedError).always(start);
+  });
+
+  test("PutAttachment", function () {
+    var shared = {}, jio, jio_s3_list = [];
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "application_name": "putAttachment1",
+      "mode": "memory"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "application_name": "putAttachment2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+    jio_s3_list[0] = jIO.createJIO(shared.s3_storage_description1, {
+      "workspace": shared.workspace
+    });
+    jio_s3_list[1] = jIO.createJIO(shared.s3_storage_description2, {
+      "workspace": shared.workspace
+    });
+    jio_s3_list.run = function (method, argument) {
+      var i, promises = [];
+      for (i = 0; i < this.length; i += 1) {
+        promises[i] = this[i][method].apply(this[i], argument);
+      }
+      return RSVP.all(promises);
+    };
+    jio_s3_list.get = function () {
+      return this.run("get", arguments);
+    };
+    jio_s3_list.getAttachmentAsBinaryString = function () {
+      return this.run("getAttachment", arguments).then(function (answers) {
+        var i, promises = [];
+        for (i = 0; i < answers.length; i += 1) {
+          promises[i] = tool.readBlobAsBinaryString(answers[i].data);
+        }
+        return RSVP.all(promises);
+      });
+    };
+
+    stop();
+
+    return reverse(jio.putAttachment({
+      "_id": "two",
+      "_attachment": "my_attachment",
+      "_data": "My Data",
+      "_content_type": "text/plain"
+    })).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "two",
+        "message": "Unable to put attachment",
+        "method": "putAttachment",
+        "reason": "Document does not exist",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Put attachment on a inexistent document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "two",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return jio.putAttachment({
+        "_id": "two",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "id": "two",
+        "method": "putAttachment",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Put attachment on a document");
+
+      // check uploaded documents
+      return jio_s3_list.get({"_id": "two"});
+
+    }).then(function (answers) {
+
+      deepEqual(answers[0].data, {
+        "_attachments": {
+          "my_attachment": {
+            "content_type": "text/plain",
+            "digest": "sha256-ebf2d770a6a2dfa135f6c81431f22fc3cbcde9ae" +
+              "e52759ca9e520d4d964c1322", // sha256("My ")
+            "length": 3
+          }
+        },
+        "_id": "two",
+        "_underscored_meta": "uvalue",
+        "data": "{\"meta\""
+      }, "Check uploaded document in sub storage 1");
+
+      deepEqual(answers[1].data, {
+        "_attachments": {
+          "my_attachment": {
+            "content_type": "text/plain",
+            "digest": "sha256-cec3a9b89b2e391393d0f68e4bc12a9fa6cf358b" +
+              "3cdf79496dc442d52b8dd528", // sha256("Data")
+            "length": 4
+          }
+        },
+        "_id": "two",
+        "_underscored_meta": "uvalue",
+        "data": ":\"data\"}"
+      }, "Check uploaded document in sub storage 2");
+
+      return jio_s3_list.getAttachmentAsBinaryString({
+        "_id": "two",
+        "_attachment": "my_attachment"
+      });
+
+    }).then(function (events) {
+
+      deepEqual(events[0].target.result, "My ",
+                "Check uploaded document in sub storage 1");
+      deepEqual(events[1].target.result, "Data",
+                "Check uploaded document in sub storage 1");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("Get", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "application_name": "get1",
+      "mode": "memory"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "application_name": "get2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.get({"_id": "three"})).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "not_found",
+        "id": "three",
+        "message": "Unable to get document",
+        "method": "get",
+        "reason": "Not Found",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Get missing document");
+
+      return jio.post({
+        "_id": "three",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return jio.get({"_id": "three"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "three",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      }, "Get posted document");
+
+      return jio.putAttachment({
+        "_id": "three",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_content_type": "text/plain"
+      });
+
+    }).then(function () {
+
+      return jio.get({"_id": "three"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "three",
+        "_underscored_meta": "uvalue",
+        "meta": "data",
+        "_attachments": {
+          "my_attachment": {
+            "length": 7,
+            "content_type": "text/plain"
+          }
+        }
+      }, "Get document with attachment informations");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+
+  test("GetAttachment", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "application_name": "getAttachment",
+      "mode": "memory"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "application_name": "getAttachment2",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.getAttachment({
+      "_id": "four",
+      "_attachment": "my_attachment"
+    }))
+
+      .then(function (answer) {
+        deepEqual(answer, {
+          "attachment": "my_attachment",
+          "error": "not_found",
+          "id": "four",
+          "message": "Unable to get attachment",
+          "method": "getAttachment",
+          "reason": "Not Found",
+          "result": "error",
+          "status": 404,
+          "statusText": "Not Found"
+        }, "Get attachment from missing document -> 404 Not Found");
+        return jio.post({
+          "_id": "four",
+          "_underscored_meta": "uvalue",
+          "meta": "data"
+        });
+      })
+      .then(function () {
+        return reverse(jio.getAttachment({
+          "_id": "four",
+          "_attachment": "my_attachment"
+        }));
+      }).then(function (answer) {
+        deepEqual(answer, {
+          "attachment": "my_attachment",
+          "error": "not_found",
+          "id": "four",
+          "message": "Unable to get attachment",
+          "method": "getAttachment",
+          "reason": "Not Found",
+          "result": "error",
+          "status": 404,
+          "statusText": "Not Found"
+        }, "Get missing attachment from document");
+        return jio.putAttachment({
+          "_id": "four",
+          "_attachment": "my_attachment",
+          "_data": "My Data",
+          "_mimetype": "text/plain"
+        });
+      })
+      .then(function () {
+        return jio.getAttachment({
+          "_id": "four",
+          "_attachment": "my_attachment"
+        });
+      }).then(function (answer) {
+        return tool.readBlobAsBinaryString(answer.data);
+      }).then(function (event) {
+        deepEqual(event.target.result, "My Data", "Get attachment");
+      })
+      .fail(unexpectedError).always(start);
+  });
+
+
+  test("RemoveAttachment", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "mode": "memory"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y",
+      "mode": "memory"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.removeAttachment({
+      "_id": "five",
+      "_attachment": "my_attachment"
+    })).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "five",
+        "message": "Unable to remove attachment",
+        "method": "removeAttachment",
+        "reason": "missing document",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Remove attachment from inexistent document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "five",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return reverse(jio.removeAttachment({
+        "_id": "five",
+        "_attachment": "my_attachment"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "five",
+        "message": "Unable to remove attachment",
+        "method": "removeAttachment",
+        "reason": "missing attachment",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Remove inexistent attachment -> 404 Not Found");
+
+      return jio.putAttachment({
+        "_id": "five",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    })
+      .then(function () {
+        return jio.removeAttachment({
+          "_id": "five",
+          "_attachment": "my_attachment"
+        });
+      })
+      .then(function (answer) {
+        deepEqual(answer, {
+          "attachment": "my_attachment",
+          "id": "five",
+          "method": "removeAttachment",
+          "result": "success",
+          "status": 204,
+          "statusText": "No Content"
+        }, "Remove attachment");
+        return jio.get({"_id": "five"});
+      }).then(function (answer) {
+        deepEqual(answer.data, {
+          "_id": "five",
+          "_underscored_meta": "uvalue",
+          "meta": "data"
+        }, "Check document");
+        return reverse(jio.getAttachment({
+          "_id": "five",
+          "_attachment": "my_attachment"
+        }));
+      }).then(function (answer) {
+        deepEqual(answer, {
+          "attachment": "my_attachment",
+          "error": "not_found",
+          "id": "five",
+          "message": "Unable to get attachment",
+          "method": "getAttachment",
+          "reason": "Not Found",
+          "result": "error",
+          "status": 404,
+          "statusText": "Not Found"
+        }, "Check attachment -> 404 Not Found");
+      })
+      .fail(unexpectedError).always(start);
+
+  });
+
+  test("Remove", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    reverse(jio.remove({"_id": "six"})).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "not_found",
+        "id": "six",
+        "message": "Unable to remove document",
+        "method": "remove",
+        "reason": "Not Found",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Remove missing document -> 404 Not Found");
+
+      return jio.post({
+        "_id": "six",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      });
+
+    }).then(function () {
+
+      return jio.putAttachment({
+        "_id": "six",
+        "_attachment": "my_attachment",
+        "_data": "My Data",
+        "_mimetype": "text/plain"
+      });
+
+    }).then(function () {
+
+      return jio.remove({"_id": "six"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "six",
+        "method": "remove",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Remove document");
+
+      return reverse(jio.getAttachment({
+        "_id": "six",
+        "_attachment": "my_attachment"
+      }));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "attachment": "my_attachment",
+        "error": "not_found",
+        "id": "six",
+        "message": "Unable to get attachment",
+        "method": "getAttachment",
+        "reason": "Not Found",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Check attachment -> 404 Not Found");
+
+      return reverse(jio.get({"_id": "six"}));
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "error": "not_found",
+        "id": "six",
+        "message": "Unable to get document",
+        "method": "get",
+        "reason": "Not Found",
+        "result": "error",
+        "status": 404,
+        "statusText": "Not Found"
+      }, "Check document -> 404 Not Found");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("Put", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucketsplit",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucketsplit_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    jio.put({
+      "_id": "seven",
+      "_underscored_meta": "uvalue",
+      "meta": "data"
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "seven",
+        "method": "put",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Put new document");
+
+      return jio.get({"_id": "seven"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "seven",
+        "_underscored_meta": "uvalue",
+        "meta": "data"
+      }, "Check document");
+
+      return jio.put({
+        "_id": "seven",
+        "_underscored_meta": "uvalue",
+        "meow": "dog"
+      });
+
+    }).then(function (answer) {
+
+      deepEqual(answer, {
+        "id": "seven",
+        "method": "put",
+        "result": "success",
+        "status": 204,
+        "statusText": "No Content"
+      }, "Put same document again");
+
+      return jio.get({"_id": "seven"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "seven",
+        "_underscored_meta": "uvalue",
+        "meow": "dog"
+      }, "Get document for check");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+  test("AllDocs", function () {
+    var shared = {}, jio;
+
+    shared.workspace = {};
+    shared.s3_storage_description1 = {
+      "type": "s3",
+      "server": "jiobucket_alldocs",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    shared.s3_storage_description2 = {
+      "type": "s3",
+      "server": "jiobucket_alldocs_bis",
+      "AWSIdentifier": "AKIAJLNYGVLTV66RHPEQ",
+      "password": "/YHoa5r2X6EUHfvP31jdYx6t75h81pAjIZ4Mt94y"
+    };
+    jio = jIO.createJIO({
+      "type": "split",
+      "storage_list": [
+        shared.s3_storage_description1,
+        shared.s3_storage_description2
+      ]
+    }, {"workspace": shared.workspace});
+
+    stop();
+
+    function prepareDatabase() {
+      var i, do_list = [];
+      function post(i) {
+        return function () {
+          return jio.post({
+            "_id": "doc" + i,
+            "_underscored_meta": "uvalue" + i,
+            "meta": "data" + i
+          });
+        };
+      }
+      function putAttachment(i) {
+        return function () {
+          return jio.putAttachment({
+            "_id": "doc" + i,
+            "_attachment": "my_attachment" + i,
+            "_data": "My Data" + i,
+            "_content_type": "text/plain"
+          });
+        };
+      }
+      for (i = 0; i < 5; i += 1) {
+        do_list.push(post(i));
+      }
+      for (i = 0; i < 2; i += 1) {
+        do_list.push(putAttachment(i));
+      }
+      return sequence(do_list);
+    }
+
+    prepareDatabase().then(function () {
+
+      return jio.get({"_id": "doc1"});
+
+    }).then(function (answer) {
+
+      deepEqual(answer.data, {
+        "_id": "doc1",
+        "_underscored_meta": "uvalue1",
+        "meta": "data1",
+        "_attachments": {
+          "my_attachment1": {
+            "length": 8,
+            "content_type": "text/plain"
+          }
+        }
+      }, "Check document");
+
+      return jio.allDocs();
+
+    }).then(function (answer) {
+
+      answer.data.rows.sort(function (a, b) {
+        return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
+      });
+
+      deepEqual(answer.data, {
+        "total_rows": 5,
+        "rows": [
+          {
+            "id": "doc0",
+            "key": "doc0",
+            "value": {}
+          },
+          {
+            "id": "doc1",
+            "key": "doc1",
+            "value": {}
+          },
+          {
+            "id": "doc2",
+            "key": "doc2",
+            "value": {}
+          },
+          {
+            "id": "doc3",
+            "key": "doc3",
+            "value": {}
+          },
+          {
+            "id": "doc4",
+            "key": "doc4",
+            "value": {}
+          }]
+      }, "AllDocs with document ids only");
+
+    }).fail(unexpectedError).always(start);
+
+  });
+
+}));