diff --git a/src/jio.storage/drivetojiomapping.js b/src/jio.storage/drivetojiomapping.js
index 46ad242b179b915b29f90f8ec76502f20a86549e..91fbfafef15736c3cc3612248be66d695d82ed0f 100644
--- a/src/jio.storage/drivetojiomapping.js
+++ b/src/jio.storage/drivetojiomapping.js
@@ -1,6 +1,6 @@
-/*jslint nomen: true, maxlen: 200*/
-/*global console, RSVP, Blob*/
-(function (jIO) {
+/*jslint nomen: true*/
+/*global RSVP, Blob*/
+(function (jIO, RSVP, Blob) {
   "use strict";
 
   /**
@@ -11,10 +11,11 @@
    */
   function FileSystemBridgeStorage(spec) {
     this._sub_storage = jIO.createJIO(spec.sub_storage);
-    this._document_key = "/.jio_documents/";
-    this._attachment_key = "/.jio_attachments/";
   }
   var DOCUMENT_EXTENSION = ".json",
+    DOCUMENT_REGEXP = new RegExp("^([\\w=]+)" +
+                                 DOCUMENT_EXTENSION + "$"),
+    DOCUMENT_KEY = "/.jio_documents/",
     ROOT = "/";
 
   FileSystemBridgeStorage.prototype.get = function (param) {
@@ -28,21 +29,22 @@
       .push(function () {
         // First get the document itself if it exists
         return context._sub_storage.getAttachment({
-          "_id": context._document_key,
+          "_id": DOCUMENT_KEY,
           "_attachment": param._id + DOCUMENT_EXTENSION
         });
       })
       .push(function (blob) {
         return new RSVP.Queue()
           .push(function () {
-            return jIO.util.readBlobAsText(blob);
+            return jIO.util.readBlobAsText(blob.data);
           })
           .push(function (text) {
             explicit_document = true;
             return JSON.parse(text.target.result);
           });
       }, function (error) {
-        if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) {
+        if ((error instanceof jIO.util.jIOError) &&
+            (error.status_code === 404)) {
           return {};
         }
         throw error;
@@ -59,13 +61,15 @@
       })
 
       .push(function (directory_document) {
-        if (directory_document._attachments.hasOwnProperty(param._id)) {
+        if ((directory_document.hasOwnProperty("_attachments")) &&
+            (directory_document._attachments.hasOwnProperty(param._id))) {
           json_document._attachments = {
             enclosure: {}
           };
         } else {
           if (!explicit_document) {
-            throw new jIO.util.jIOError("Cannot find document", 404);
+            throw new jIO.util.jIOError("Cannot find document " + param._id,
+                                        404);
           }
         }
         return json_document;
@@ -73,38 +77,28 @@
 
   };
 
-  FileSystemBridgeStorage.prototype.post = function (param) {
-    var doc_id = param._id;
-
-    if (doc_id === undefined) {
-      doc_id = jIO.util.generateUuid();
-    }
-
-    param._id = doc_id;
-    return this.put(param);
-  };
-
   FileSystemBridgeStorage.prototype.put = function (param) {
     var context = this,
       doc_id = param._id;
     // XXX Handle conflict!
-    // XXX Put empty enclosure directly if json is empty
 
     return context._sub_storage.putAttachment({
-      "_id": context._document_key,
+      "_id": DOCUMENT_KEY,
       "_attachment": doc_id + DOCUMENT_EXTENSION,
       "_blob": new Blob([JSON.stringify(param)], {type: "application/json"})
     })
       .push(undefined, function (error) {
-        if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) {
+        if ((error instanceof jIO.util.jIOError) &&
+            (error.status_code === 404)) {
           return context._sub_storage.put({
-            "_id": context._document_key
+            "_id": DOCUMENT_KEY
           })
             .push(function () {
               return context._sub_storage.putAttachment({
-                "_id": context._document_key,
+                "_id": DOCUMENT_KEY,
                 "_attachment": doc_id + DOCUMENT_EXTENSION,
-                "_blob": new Blob([JSON.stringify(param)], {type: "application/json"})
+                "_blob": new Blob([JSON.stringify(param)],
+                                  {type: "application/json"})
               });
             });
         }
@@ -131,7 +125,8 @@
       })
 
       .push(undefined, function (error) {
-        if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) {
+        if ((error instanceof jIO.util.jIOError) &&
+            (error.status_code === 404)) {
           got_error = true;
           return;
         }
@@ -141,14 +136,15 @@
       // Second, try to remove explicit doc
       .push(function () {
         return context._sub_storage.removeAttachment({
-          "_id": context._document_key,
+          "_id": DOCUMENT_KEY,
           "_attachment": doc_id + DOCUMENT_EXTENSION
         });
       })
 
       .push(undefined, function (error) {
-        if ((!got_error) && (error instanceof jIO.util.jIOError) && (error.status_code === 404)) {
-          return;
+        if ((!got_error) && (error instanceof jIO.util.jIOError) &&
+            (error.status_code === 404)) {
+          return doc_id;
         }
         throw error;
       });
@@ -156,10 +152,7 @@
   };
 
   FileSystemBridgeStorage.prototype.hasCapacity = function (capacity) {
-    if (capacity === "list") {
-      return true;
-    }
-    return false;
+    return (capacity === "list");
   };
 
   FileSystemBridgeStorage.prototype.buildQuery = function () {
@@ -171,18 +164,21 @@
 
       .push(function () {
         return context._sub_storage.get({
-          "_id": context._document_key
+          "_id": DOCUMENT_KEY
         });
       })
       .push(function (result) {
         var key;
         for (key in result._attachments) {
           if (result._attachments.hasOwnProperty(key)) {
-            result_dict[key.slice(0, key.length - DOCUMENT_EXTENSION.length)] = null;
+            if (DOCUMENT_REGEXP.test(key)) {
+              result_dict[DOCUMENT_REGEXP.exec(key)[1]] = null;
+            }
           }
         }
       }, function (error) {
-        if ((error instanceof jIO.util.jIOError) && (error.status_code === 404)) {
+        if ((error instanceof jIO.util.jIOError) &&
+            (error.status_code === 404)) {
           return;
         }
         throw error;
@@ -224,7 +220,8 @@
 
   FileSystemBridgeStorage.prototype.getAttachment = function (param) {
     if (param._attachment !== "enclosure") {
-      throw new Error("Only support 'enclosure' attachment");
+      throw new jIO.util.jIOError("Only support 'enclosure' attachment",
+                                  400);
     }
 
     return this._sub_storage.getAttachment({
@@ -235,7 +232,8 @@
 
   FileSystemBridgeStorage.prototype.putAttachment = function (param) {
     if (param._attachment !== "enclosure") {
-      throw new Error("Only support 'enclosure' attachment");
+      throw new jIO.util.jIOError("Only support 'enclosure' attachment",
+                                  400);
     }
 
     return this._sub_storage.putAttachment({
@@ -247,7 +245,8 @@
 
   FileSystemBridgeStorage.prototype.removeAttachment = function (param) {
     if (param._attachment !== "enclosure") {
-      throw new Error("Only support 'enclosure' attachment");
+      throw new jIO.util.jIOError("Only support 'enclosure' attachment",
+                                  400);
     }
 
     return this._sub_storage.removeAttachment({
@@ -258,4 +257,4 @@
 
   jIO.addStorage('drivetojiomapping', FileSystemBridgeStorage);
 
-}(jIO));
+}(jIO, RSVP, Blob));
diff --git a/test/jio.storage/drivetojiomapping.tests.js b/test/jio.storage/drivetojiomapping.tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..518b6a4cd4c0b8473c7aec525e29789f749b571d
--- /dev/null
+++ b/test/jio.storage/drivetojiomapping.tests.js
@@ -0,0 +1,1061 @@
+/*jslint nomen: true*/
+/*global Blob*/
+(function (jIO, QUnit, Blob) {
+  "use strict";
+  var test = QUnit.test,
+    stop = QUnit.stop,
+    start = QUnit.start,
+    ok = QUnit.ok,
+    expect = QUnit.expect,
+    deepEqual = QUnit.deepEqual,
+    equal = QUnit.equal,
+    module = QUnit.module;
+
+  /////////////////////////////////////////////////////////////////
+  // Custom test substorage definition
+  /////////////////////////////////////////////////////////////////
+  function Storage200() {
+    return this;
+  }
+  jIO.addStorage('drivetojiomapping200', Storage200);
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.constructor
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.constructor");
+  test("create substorage", function () {
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+
+    ok(jio.__storage._sub_storage instanceof jio.constructor);
+    equal(jio.__storage._sub_storage.__type, "drivetojiomapping200");
+
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.get
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.get");
+
+  test("get non existent document", function () {
+    stop();
+    expect(5);
+
+    function StorageGetNoDocument() {
+      return this;
+    }
+    StorageGetNoDocument.prototype.getAttachment = function (options) {
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "getAttachment");
+      throw new jIO.util.jIOError("Cannot find subattachment", 404);
+    };
+    StorageGetNoDocument.prototype.get = function (options) {
+      deepEqual(options, {"_id": "/"}, "Get document");
+      return {
+        "_id": "/"
+      };
+    };
+
+    jIO.addStorage('drivetojiomappinggetnodocument', StorageGetNoDocument);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappinggetnodocument"
+      }
+    });
+
+    jio.get({"_id": "bar"})
+      .then(function () {
+        ok(false);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Cannot find document bar");
+        equal(error.status_code, 404);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get document with only one attachment", function () {
+    stop();
+    expect(3);
+
+    function StorageGetOnlyAttachment() {
+      return this;
+    }
+    StorageGetOnlyAttachment.prototype.getAttachment = function (options) {
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "getAttachment");
+      throw new jIO.util.jIOError("Cannot find subattachment", 404);
+    };
+    StorageGetOnlyAttachment.prototype.get = function (options) {
+      deepEqual(options, {"_id": "/"}, "Get document");
+      return {
+        "_id": "/",
+        "_attachments": {
+          "bar": {}
+        }
+      };
+    };
+
+    jIO.addStorage('drivetojiomappinggetonlyattachment',
+                   StorageGetOnlyAttachment);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappinggetonlyattachment"
+      }
+    });
+
+    jio.get({"_id": "bar"})
+      .then(function (result) {
+        deepEqual(result, {
+          "_id": "bar",
+          "_attachments": {
+            enclosure: {}
+          }
+        });
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get document with only one document", function () {
+    stop();
+    expect(3);
+
+    function StorageGetOnlyDocument() {
+      return this;
+    }
+    StorageGetOnlyDocument.prototype.getAttachment = function (options) {
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "getAttachment");
+      return {data: new Blob([JSON.stringify({title: "foo"})])};
+    };
+    StorageGetOnlyDocument.prototype.get = function (options) {
+      deepEqual(options, {"_id": "/"}, "Get document");
+      return {
+        "_id": "/"
+      };
+    };
+
+    jIO.addStorage('drivetojiomappinggetonlydocument', StorageGetOnlyDocument);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappinggetonlydocument"
+      }
+    });
+
+    jio.get({"_id": "bar"})
+      .then(function (result) {
+        deepEqual(result, {
+          "_id": "bar",
+          "title": "foo"
+        });
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("get document with one document and one attachment", function () {
+    stop();
+    expect(3);
+
+    function StorageGetBoth() {
+      return this;
+    }
+    StorageGetBoth.prototype.getAttachment = function (options) {
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "getAttachment");
+      return {data: new Blob([JSON.stringify({title: "foo"})])};
+    };
+    StorageGetBoth.prototype.get = function (options) {
+      deepEqual(options, {"_id": "/"}, "Get document");
+      return {
+        "_id": "/",
+        "_attachments": {
+          "bar": {}
+        }
+      };
+    };
+
+    jIO.addStorage('drivetojiomappinggetboth', StorageGetBoth);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappinggetboth"
+      }
+    });
+
+    jio.get({"_id": "bar"})
+      .then(function (result) {
+        deepEqual(result, {
+          "_id": "bar",
+          "title": "foo",
+          "_attachments": {
+            enclosure: {}
+          }
+        });
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.put
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.put");
+  test("put called substorage put", function () {
+    stop();
+    expect(4);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+    Storage200.prototype.putAttachment = function (param) {
+      var blob = param._blob;
+      delete param._blob;
+      equal(blob.type, "application/json", "Blob type is OK");
+      deepEqual(param, {
+        "_id": "/.jio_documents/",
+        "_attachment": "bar.json"
+      }, "putAttachment 200 called");
+
+      return jIO.util.readBlobAsText(blob)
+        .then(function (result) {
+          deepEqual(JSON.parse(result.target.result),
+                    {"_id": "bar", "title": "bartitle"},
+                    "JSON is in blob");
+          return param._id;
+        });
+
+    };
+
+    jio.put({"_id": "bar", "title": "bartitle"})
+      .then(function (result) {
+        equal(result, "bar");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("automatically create subdocuments", function () {
+    stop();
+    expect(8);
+
+    var call_count = 0,
+      jio;
+
+    function StorageCreateSubDocument() {
+      return this;
+    }
+    StorageCreateSubDocument.prototype.putAttachment = function (param) {
+      call_count += 1;
+      var blob = param._blob;
+      delete param._blob;
+      equal(blob.type, "application/json", "Blob type is OK");
+      deepEqual(param, {
+        "_id": "/.jio_documents/",
+        "_attachment": "bar.json"
+      }, "putAttachment 200 called");
+
+      return jIO.util.readBlobAsText(blob)
+        .then(function (result) {
+          deepEqual(JSON.parse(result.target.result),
+                    {"_id": "bar", "title": "bartitle"},
+                    "JSON is in blob");
+          if (call_count === 1) {
+            throw new jIO.util.jIOError("Cannot access subdocument", 404);
+          }
+          return "PutSubAttachment OK";
+        });
+    };
+
+    StorageCreateSubDocument.prototype.put = function (param) {
+      deepEqual(param, {
+        "_id": "/.jio_documents/"
+      }, "put 200 called");
+      return "PutSubDocument OK";
+    };
+
+    jIO.addStorage('drivetojiomappingcreatesubdocument',
+                   StorageCreateSubDocument);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingcreatesubdocument"
+      }
+    });
+
+    jio.put({"_id": "bar", "title": "bartitle"})
+      .then(function (result) {
+        equal(result, "bar");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.remove
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.remove");
+
+  test("remove non existent document", function () {
+    var call_count = 0,
+      jio;
+    stop();
+    expect(6);
+
+    function StorageRemoveNoDocument() {
+      return this;
+    }
+    StorageRemoveNoDocument.prototype.removeAttachment = function (options) {
+      call_count += 1;
+      if (call_count === 1) {
+        deepEqual(options, {"_id": "/",
+                            "_attachment": "bar"},
+                  "removeAttachment");
+        throw new jIO.util.jIOError("Cannot find subattachment", 404);
+      }
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "removeAttachment");
+      throw new jIO.util.jIOError("Cannot find subdocument", 404);
+    };
+
+    jIO.addStorage('drivetojiomappingremovenodocument',
+                   StorageRemoveNoDocument);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingremovenodocument"
+      }
+    });
+
+    jio.remove({"_id": "bar"})
+      .then(function () {
+        ok(false);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Cannot find subdocument");
+        equal(error.status_code, 404);
+      })
+      .then(function () {
+        equal(call_count, 2);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("remove document with only one attachment", function () {
+    var call_count = 0,
+      jio;
+    stop();
+    expect(4);
+
+    function StorageRemoveOnlyAttachment() {
+      return this;
+    }
+    StorageRemoveOnlyAttachment.prototype.removeAttachment =
+      function (options) {
+        call_count += 1;
+        if (call_count === 1) {
+          deepEqual(options, {"_id": "/",
+                              "_attachment": "bar"},
+                    "removeAttachment");
+          return "Removed";
+        }
+        deepEqual(options, {"_id": "/.jio_documents/",
+                            "_attachment": "bar.json"},
+                  "removeAttachment");
+        throw new jIO.util.jIOError("Cannot find subdocument", 404);
+      };
+
+    jIO.addStorage('drivetojiomappingremoveonlyattachment',
+                   StorageRemoveOnlyAttachment);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingremoveonlyattachment"
+      }
+    });
+
+    jio.remove({"_id": "bar"})
+      .then(function (result) {
+        equal(result, "bar");
+        equal(call_count, 2);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("remove document with only one document", function () {
+    var call_count = 0,
+      jio;
+    stop();
+    expect(4);
+
+    function StorageRemoveOnlyDocument() {
+      return this;
+    }
+    StorageRemoveOnlyDocument.prototype.removeAttachment = function (options) {
+      call_count += 1;
+      if (call_count === 1) {
+        deepEqual(options, {"_id": "/",
+                            "_attachment": "bar"},
+                  "removeAttachment");
+        throw new jIO.util.jIOError("Cannot find subattachment", 404);
+      }
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "removeAttachment");
+      return "Removed";
+    };
+
+    jIO.addStorage('drivetojiomappingremoveonlydocument',
+                   StorageRemoveOnlyDocument);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingremoveonlydocument"
+      }
+    });
+
+    jio.remove({"_id": "bar"})
+      .then(function (result) {
+        equal(result, "Removed");
+        equal(call_count, 2);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("remove document with one document and one attachment", function () {
+    var call_count = 0,
+      jio;
+    stop();
+    expect(4);
+
+    function StorageRemoveBoth() {
+      return this;
+    }
+    StorageRemoveBoth.prototype.removeAttachment = function (options) {
+      call_count += 1;
+      if (call_count === 1) {
+        deepEqual(options, {"_id": "/",
+                            "_attachment": "bar"},
+                  "removeAttachment");
+        return "Removed attachment";
+      }
+      deepEqual(options, {"_id": "/.jio_documents/",
+                          "_attachment": "bar.json"},
+                "removeAttachment");
+      return "Removed document";
+    };
+
+    jIO.addStorage('drivetojiomappingremoveboth', StorageRemoveBoth);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingremoveboth"
+      }
+    });
+
+    jio.remove({"_id": "bar"})
+      .then(function (result) {
+        equal(result, "Removed document");
+        equal(call_count, 2);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.getAttachment
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.getAttachment");
+  test("reject non enclosure attachment", function () {
+    stop();
+    expect(3);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+
+    jio.getAttachment({"_id": "bar", "_attachment": "foo"})
+      .then(function () {
+        ok(false);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Only support 'enclosure' attachment");
+        equal(error.status_code, 400);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("getAttachment called substorage getAttachment", function () {
+    stop();
+    expect(2);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    }),
+      blob = new Blob(["foo"]);
+
+    Storage200.prototype.getAttachment = function (param) {
+      deepEqual(param, {"_id": "/",
+                        "_attachment": "bar"},
+                "getAttachment 200 called");
+      return {data: blob};
+    };
+
+    jio.getAttachment({"_id": "bar", "_attachment": "enclosure"})
+      .then(function (result) {
+        equal(result.data, blob);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.putAttachment
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.putAttachment");
+  test("reject non enclosure attachment", function () {
+    stop();
+    expect(3);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+
+    jio.putAttachment({"_id": "bar", "_attachment": "foo",
+                       "_blob": new Blob(["foo"])})
+      .then(function () {
+        ok(false);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Only support 'enclosure' attachment");
+        equal(error.status_code, 400);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("putAttachment called substorage putAttachment", function () {
+    stop();
+    expect(2);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    }),
+      blob = new Blob(["foo"]);
+
+    Storage200.prototype.putAttachment = function (param) {
+      deepEqual(param, {"_id": "/",
+                        "_blob": blob,
+                        "_attachment": "bar"},
+                "putAttachment 200 called");
+      return "Put";
+    };
+
+    jio.putAttachment({"_id": "bar", "_attachment": "enclosure", "_blob": blob})
+      .then(function (result) {
+        equal(result, "Put");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.removeAttachment
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.removeAttachment");
+  test("reject non enclosure attachment", function () {
+    stop();
+    expect(3);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+
+    jio.removeAttachment({"_id": "bar", "_attachment": "foo"})
+      .then(function () {
+        ok(false);
+      })
+      .fail(function (error) {
+        ok(error instanceof jIO.util.jIOError);
+        equal(error.message, "Only support 'enclosure' attachment");
+        equal(error.status_code, 400);
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("removeAttachment called substorage removeAttachment", function () {
+    stop();
+    expect(2);
+
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+
+    Storage200.prototype.removeAttachment = function (param) {
+      deepEqual(param, {"_id": "/",
+                        "_attachment": "bar"},
+                "removeAttachment 200 called");
+      return "Removed";
+    };
+
+    jio.removeAttachment({"_id": "bar", "_attachment": "enclosure"})
+      .then(function (result) {
+        equal(result, "Removed");
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.hasCapacity
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.hasCapacity");
+  test("can list documents", function () {
+    var jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomapping200"
+      }
+    });
+
+    ok(jio.hasCapacity("list"));
+  });
+
+  /////////////////////////////////////////////////////////////////
+  // driveToJioMapping.buildQuery
+  /////////////////////////////////////////////////////////////////
+  module("driveToJioMapping.buildQuery");
+
+  test("no document directory, no attachments: empty result", function () {
+    stop();
+    expect(3);
+
+    var call_count = 0,
+      jio;
+
+    function StorageAllDocsNoDirectory() {
+      return this;
+    }
+
+    StorageAllDocsNoDirectory.prototype.get = function (param) {
+      call_count += 1;
+      if (call_count === 1) {
+        deepEqual(param, {
+          "_id": "/.jio_documents/"
+        }, "get documents called");
+        throw new jIO.util.jIOError("Cannot access subdocument", 404);
+      }
+
+      deepEqual(param, {
+        "_id": "/"
+      }, "get attachments called");
+      return {
+        "_id": "/"
+      };
+    };
+
+    jIO.addStorage('drivetojiomappingalldocsnodirectory',
+                   StorageAllDocsNoDirectory);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingalldocsnodirectory"
+      }
+    });
+
+    jio.allDocs()
+      .then(function (result) {
+        deepEqual(result, {
+          data: {
+            rows: [],
+            total_rows: 0
+          }
+        });
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("empty document directory, no attachments: empty result", function () {
+    stop();
+    expect(3);
+
+    var call_count = 0,
+      jio;
+
+    function StorageAllDocsEmpty() {
+      return this;
+    }
+
+    StorageAllDocsEmpty.prototype.get = function (param) {
+      call_count += 1;
+      if (call_count === 1) {
+        deepEqual(param, {
+          "_id": "/.jio_documents/"
+        }, "get documents called");
+        return {
+          "_id": "/.jio_documents/"
+        };
+      }
+
+      deepEqual(param, {
+        "_id": "/"
+      }, "get attachments called");
+      return {
+        "_id": "/"
+      };
+    };
+
+    jIO.addStorage('drivetojiomappingalldocsempty',
+                   StorageAllDocsEmpty);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingalldocsempty"
+      }
+    });
+
+    jio.allDocs()
+      .then(function (result) {
+        deepEqual(result, {
+          data: {
+            rows: [],
+            total_rows: 0
+          }
+        });
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+  test("no document directory, attachments found: attachments as result",
+       function () {
+      stop();
+      expect(3);
+
+      var call_count = 0,
+        jio;
+
+      function StorageAllDocsAttachmentsOnly() {
+        return this;
+      }
+
+      StorageAllDocsAttachmentsOnly.prototype.get = function (param) {
+        call_count += 1;
+        if (call_count === 1) {
+          deepEqual(param, {
+            "_id": "/.jio_documents/"
+          }, "get documents called");
+          throw new jIO.util.jIOError("Cannot access subdocument", 404);
+        }
+
+        deepEqual(param, {
+          "_id": "/"
+        }, "get attachments called");
+        return {
+          "_id": "/",
+          "_attachments": {
+            foo: {},
+            bar: {}
+          }
+        };
+      };
+
+      jIO.addStorage('drivetojiomappingalldocsattachmentsonly',
+                     StorageAllDocsAttachmentsOnly);
+
+      jio = jIO.createJIO({
+        type: "drivetojiomapping",
+        sub_storage: {
+          type: "drivetojiomappingalldocsattachmentsonly"
+        }
+      });
+
+      jio.allDocs()
+        .then(function (result) {
+          deepEqual(result, {
+            data: {
+              rows: [{
+                id: "foo",
+                value: {}
+              }, {
+                id: "bar",
+                value: {}
+              }],
+              total_rows: 2
+            }
+          });
+        })
+        .fail(function (error) {
+          ok(false, error);
+        })
+        .always(function () {
+          start();
+        });
+    });
+
+  test("document directory, no attachments: json document as result",
+       function () {
+      stop();
+      expect(3);
+
+      var call_count = 0,
+        jio;
+
+      function StorageAllDocsFilterDocument() {
+        return this;
+      }
+
+      StorageAllDocsFilterDocument.prototype.get = function (param) {
+        call_count += 1;
+        if (call_count === 1) {
+          deepEqual(param, {
+            "_id": "/.jio_documents/"
+          }, "get documents called");
+          return {
+            "_id": "/",
+            "_attachments": {
+              "foo.json": {},
+              "bar.json": {},
+              "foobar.pasjson": {}
+            }
+          };
+        }
+
+        deepEqual(param, {
+          "_id": "/"
+        }, "get attachments called");
+        return {
+          "_id": "/"
+        };
+      };
+
+      jIO.addStorage('drivetojiomappingalldocsfilterdocument',
+                     StorageAllDocsFilterDocument);
+
+      jio = jIO.createJIO({
+        type: "drivetojiomapping",
+        sub_storage: {
+          type: "drivetojiomappingalldocsfilterdocument"
+        }
+      });
+
+      jio.allDocs()
+        .then(function (result) {
+          deepEqual(result, {
+            data: {
+              rows: [{
+                id: "foo",
+                value: {}
+              }, {
+                id: "bar",
+                value: {}
+              }],
+              total_rows: 2
+            }
+          });
+        })
+        .fail(function (error) {
+          ok(false, error);
+        })
+        .always(function () {
+          start();
+        });
+    });
+
+  test("document directory, attachments found: merge result", function () {
+    stop();
+    expect(3);
+
+    var call_count = 0,
+      jio;
+
+    function StorageAllDocsBoth() {
+      return this;
+    }
+
+    StorageAllDocsBoth.prototype.get = function (param) {
+      call_count += 1;
+      if (call_count === 1) {
+        deepEqual(param, {
+          "_id": "/.jio_documents/"
+        }, "get documents called");
+        return {
+          "_id": "/",
+          "_attachments": {
+            "foo.json": {},
+            "bar.json": {}
+          }
+        };
+      }
+
+      deepEqual(param, {
+        "_id": "/"
+      }, "get attachments called");
+      return {
+        "_id": "/",
+        "_attachments": {
+          "bar": {},
+          "foobar": {}
+        }
+      };
+    };
+
+    jIO.addStorage('drivetojiomappingalldocsboth',
+                   StorageAllDocsBoth);
+
+    jio = jIO.createJIO({
+      type: "drivetojiomapping",
+      sub_storage: {
+        type: "drivetojiomappingalldocsboth"
+      }
+    });
+
+    jio.allDocs()
+      .then(function (result) {
+        deepEqual(result, {
+          data: {
+            rows: [{
+              id: "foo",
+              value: {}
+            }, {
+              id: "bar",
+              value: {}
+            }, {
+              id: "foobar",
+              value: {}
+            }],
+            total_rows: 3
+          }
+        });
+      })
+      .fail(function (error) {
+        ok(false, error);
+      })
+      .always(function () {
+        start();
+      });
+  });
+
+}(jIO, QUnit, Blob));
diff --git a/test/tests.html b/test/tests.html
index 9fa660cb908c3a90dda4e32645a874c123b4d882..3607480e3f20fbaccdb2e5a97d4f2498fd17cd60 100644
--- a/test/tests.html
+++ b/test/tests.html
@@ -30,6 +30,7 @@
   <script src="jio.storage/localstorage.tests.js"></script>
   <script src="jio.storage/documentstorage.tests.js"></script>
   <script src="jio.storage/davstorage.tests.js"></script>
+  <script src="jio.storage/drivetojiomapping.tests.js"></script>
 
   <!--script src="jio.storage/unionstorage.tests.js"></script-->