/*jslint indent: 2, maxlen: 80, nomen: true */
/*global module, test, stop, start, expect, ok, deepEqual, location, sinon,
  davstorage_spec, promy, jIO, test_util, dav_storage, btoa */

(function () {
  "use strict";

  var spec, use_fake_server = true;
  if (typeof davstorage_spec === 'object') {
    use_fake_server = false;
    spec = dav_storage.createDescription(
      davstorage_spec.url,
      davstorage_spec.auth_type,
      davstorage_spec.realm,
      davstorage_spec.username,
      davstorage_spec.password
    );
  } else {
    spec = dav_storage.createDescription(
      "http://localhost",
      "none"
    );
  }

  module("Dav Storage");

  function success(promise) {
    var deferred = new promy.Deferred();
    promise.then(
      deferred.resolve.bind(deferred),
      deferred.resolve.bind(deferred),
      deferred.notify.bind(deferred)
    );
    return deferred.promise;
  }

  /**
   * Tested with local webDav server
   *
   * Used header are:
   * - Header always set Cache-Control "no-cache" # "private", "public",
   *   "<seconds>" or "no-store" ("no-cache")
   * - Header always set Access-Control-Max-Age "0"
   * - Header always set Access-Control-Allow-Credentials "true"
   * - Header always set Access-Control-Allow-Origin "*"
   * - Header always set Access-Control-Allow-Methods "OPTIONS, GET, HEAD,
   *   POST, PUT, DELETE, PROPFIND"
   * - Header always set Access-Control-Allow-Headers "Content-Type,
   *   X-Requested-With, X-HTTP-Method-Override, Accept, Authorization,
   *   Depth"
   */
  test("Scenario", 30, function () {

    var server, responses = [], shared = {}, jio = jIO.createJIO(spec, {
      "workspace": {},
      "max_retry": 2
    });

    stop();

    if (use_fake_server) {
      /*jslint regexp: true */
      server = sinon.fakeServer.create();
      server.autoRespond = true;
      server.autoRespondAfter = 5;
      server.respondWith(/.*/, function (xhr) {
        var response = responses.shift();
        if (response) {
          return xhr.respond.apply(xhr, response);
        }
        ok(false, "No response associated to the latest request!");
      });
    } else {
      responses.push = function () {
        return;
      };
      server = {restore: function () {
        return;
      }};
    }

    function postNewDocument() {
      responses.push([404, {}, '']); // GET
      responses.push([201, {}, '']); // PUT
      return jio.post({"title": "Unique ID"});
    }

    function postNewDocumentTest(answer) {
      var uuid = answer.id;
      answer.id = "<uuid>";
      deepEqual(answer, {
        "id": "<uuid>",
        "method": "post",
        "result": "success",
        "status": 201,
        "statusText": "Created"
      }, "Post a new document");
      ok(test_util.isUuid(uuid), "New document id should look like " +
         "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + uuid);
      shared.created_document_id = uuid;
    }

    function getCreatedDocument() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": shared.created_document_id,
        "title": "Unique ID"
      })]); // GET
      return jio.get({"_id": shared.created_document_id});
    }

    function getCreatedDocumentTest(answer) {
      deepEqual(answer, {
        "data": {
          "_id": shared.created_document_id,
          "title": "Unique ID"
        },
        "id": shared.created_document_id,
        "method": "get",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "Get new document");
    }

    function postSpecificDocument() {
      responses.push([404, {}, '']); // GET
      responses.push([201, {}, '']); // PUT
      return jio.post({"_id": "b", "title": "Bee"});
    }

    function postSpecificDocumentTest(answer) {
      deepEqual(answer, {
        "id": "b",
        "method": "post",
        "result": "success",
        "status": 201,
        "statusText": "Created"
      }, "Post specific document");
    }

    function listDocuments() {
      responses.push([
        207,
        {"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-4e6bb383e5fbb"</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:response xmlns:lp2="http://apache.org/dav/props/" ' +
          'xmlns:lp1="DAV:">' +
          '<D:href>/uploads/' + shared.created_document_id + '</D:href>' +
          '<D:propstat>' +
          '<D:prop>' +
          '<lp1:resourcetype/>' +
          '<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>' +
          '<lp1:getcontentlength>66</lp1:getcontentlength>' +
          '<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT' +
          '</lp1:getlastmodified>' +
          '<lp1:getetag>"20529-42-4e6bb383d0d30"</lp1:getetag>' +
          '<lp2:executable>F</lp2:executable>' +
          '<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:prop>' +
          '<D:status>HTTP/1.1 200 OK</D:status>' +
          '</D:propstat>' +
          '</D:response>' +
          '<D:response xmlns:lp2="http://apache.org/dav/props/" ' +
          'xmlns:lp1="DAV:">' +
          '<D:href>/uploads/b</D:href>' +
          '<D:propstat>' +
          '<D:prop>' +
          '<lp1:resourcetype/>' +
          '<lp1:creationdate>2013-09-19T11:54:43Z</lp1:creationdate>' +
          '<lp1:getcontentlength>25</lp1:getcontentlength>' +
          '<lp1:getlastmodified>Thu, 19 Sep 2013 11:54:43 GMT' +
          '</lp1:getlastmodified>' +
          '<lp1:getetag>"20da3-19-4e6bb383e5fbb"</lp1:getetag>' +
          '<lp2:executable>F</lp2:executable>' +
          '<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:prop>' +
          '<D:status>HTTP/1.1 200 OK</D:status>' +
          '</D:propstat>' +
          '</D:response>' +
          '</D:multistatus>'
      ]); // PROPFIND
      return jio.allDocs();
    }

    function list2DocumentsTest(answer) {
      if (answer && answer.data && Array.isArray(answer.data.rows)) {
        answer.data.rows.sort(function (a) {
          return a.id === "b" ? 1 : 0;
        });
      }
      deepEqual(answer, {
        "data": {
          "total_rows": 2,
          "rows": [{
            "id": shared.created_document_id,
            "value": {}
          }, {
            "id": "b",
            "value": {}
          }]
        },
        "method": "allDocs",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "List 2 documents");
    }

    function removeCreatedDocument() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": shared.created_document_id,
        "title": "Unique ID"
      })]); // GET
      responses.push([204, {}, '']); // DELETE
      return jio.remove({"_id": shared.created_document_id});
    }

    function removeCreatedDocumentTest(answer) {
      deepEqual(answer, {
        "id": shared.created_document_id,
        "method": "remove",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Remove first document.");
    }

    function removeSpecificDocument() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "b",
        "title": "Bee"
      })]); // GET
      responses.push([204, {}, '']); // DELETE
      return jio.remove({"_id": "b"});
    }

    function removeSpecificDocumentTest(answer) {
      deepEqual(answer, {
        "id": "b",
        "method": "remove",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Remove second document.");
    }

    function listEmptyStorage() {
      responses.push([
        207,
        {"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();
    }

    function listEmptyStorageTest(answer) {
      deepEqual(answer, {
        "data": {
          "total_rows": 0,
          "rows": []
        },
        "method": "allDocs",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "List empty storage");
    }

    function putNewDocument() {
      responses.push([404, {}, '']); // GET
      responses.push([201, {}, '']); // PUT
      return jio.put({"_id": "a", "title": "Hey"});
    }

    function putNewDocumentTest(answer) {
      deepEqual(answer, {
        "id": "a",
        "method": "put",
        "result": "success",
        "status": 201,
        "statusText": "Created"
      }, "Put new document");
    }

    function getCreatedDocument2() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hey"
      })]); // GET
      return jio.get({"_id": "a"});
    }

    function getCreatedDocument2Test(answer) {
      deepEqual(answer, {
        "data": {
          "_id": "a",
          "title": "Hey"
        },
        "id": "a",
        "method": "get",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "Get new document");
    }

    function postSameDocument() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hey"
      })]); // GET
      return success(jio.post({"_id": "a", "title": "Hoo"}));
    }

    function postSameDocumentTest(answer) {
      deepEqual(answer, {
        "error": "conflict",
        "id": "a",
        "message": "DavStorage, cannot overwrite document metadata.",
        "method": "post",
        "reason": "Document exists",
        "result": "error",
        "status": 409,
        "statusText": "Conflict"
      }, "Unable to post the same document (conflict)");
    }

    function createAttachment() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hey"
      })]); // GET
      responses.push([201, {}, '']); // PUT (attachment)
      responses.push([204, {}, '']); // PUT (metadata)
      return jio.putAttachment({
        "_id": "a",
        "_attachment": "aa",
        "_data": "aaa",
        "_content_type": "text/plain"
      });
    }

    function createAttachmentTest(answer) {
      deepEqual(answer, {
        "attachment": "aa",
        "digest": "sha256-9834876dcfb05cb167a5c24953eba58c4" +
          "ac89b1adf57f28f2f9d09af107ee8f0",
        "id": "a",
        "method": "putAttachment",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Create new attachment");
    }

    function updateAttachment() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hey",
        "_attachments": {
          "aa": {
            "content_type": "text/plain",
            "digest": "sha256-9834876dcfb05cb167a5c24953eba58c4" +
              "ac89b1adf57f28f2f9d09af107ee8f0",
            "length": 3
          }
        }
      })]); // GET
      responses.push([204, {}, '']); // PUT (attachment)
      responses.push([204, {}, '']); // PUT (metadata)
      return jio.putAttachment({
        "_id": "a",
        "_attachment": "aa",
        "_data": "aab",
        "_content_type": "text/plain"
      });
    }

    function updateAttachmentTest(answer) {
      deepEqual(answer, {
        "attachment": "aa",
        "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
          "0728e095ff24218119d51bd22475363",
        "id": "a",
        "method": "putAttachment",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Update last attachment");
    }

    function createAnotherAttachment() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hey",
        "_attachments": {
          "aa": {
            "content_type": "text/plain",
            "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
              "0728e095ff24218119d51bd22475363",
            "length": 3
          }
        }
      })]); // GET
      responses.push([201, {}, '']); // PUT (attachment)
      responses.push([204, {}, '']); // PUT (metadata)
      return jio.putAttachment({
        "_id": "a",
        "_attachment": "ab",
        "_data": "aba",
        "_content_type": "text/plain"
      });
    }

    function createAnotherAttachmentTest(answer) {
      deepEqual(answer, {
        "attachment": "ab",
        "digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
          "ed343e6c739e54131fcb3a56e4bc1bd",
        "id": "a",
        "method": "putAttachment",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Create another attachment");
    }

    function updateLastDocument() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hey",
        "_attachments": {
          "aa": {
            "content_type": "text/plain",
            "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
              "0728e095ff24218119d51bd22475363",
            "length": 3
          },
          "ab": {
            "content_type": "text/plain",
            "digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
              "ed343e6c739e54131fcb3a56e4bc1bd",
            "length": 3
          }
        }
      })]); // GET
      responses.push([204, {}, '']); // PUT
      return jio.put({"_id": "a", "title": "Hoo"});
    }

    function updateLastDocumentTest(answer) {
      deepEqual(answer, {
        "id": "a",
        "method": "put",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Update document metadata");
    }

    function getFirstAttachment() {
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, JSON.stringify({
        "_id": "a",
        "title": "Hoo",
        "_attachments": {
          "aa": {
            "content_type": "text/plain",
            "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
              "0728e095ff24218119d51bd22475363",
            "length": 3
          },
          "ab": {
            "content_type": "text/plain",
            "digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
              "ed343e6c739e54131fcb3a56e4bc1bd",
            "length": 3
          }
        }
      })]); // GET
      responses.push([200, {
        "Content-Type": "application/octet-stream"
      }, "aab"]); // GET
      return jio.getAttachment({"_id": "a", "_attachment": "aa"});
    }

    function getFirstAttachmentTest(answer) {
      var blob = answer.data;
      answer.data = "<blob>";
      deepEqual(answer, {
        "attachment": "aa",
        "data": "<blob>",
        "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
          "0728e095ff24218119d51bd22475363",
        "id": "a",
        "method": "getAttachment",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "Get first attachment");
      return jIO.util.readBlobAsText(blob).then(function (e) {
        deepEqual(blob.type, "text/plain", "Check blob type");
        deepEqual(e.target.result, "aab", "Check blob text content");
      }, function (err) {
        deepEqual(err, "no error", "Check blob text content");
      });
    }

    function getSecondAttachment() {
      return jio.getAttachment({"_id": "a", "_attachment": "ab"});
    }

    function getSecondAttachmentTest(answer) {
      var blob = answer.data;
      answer.data = "<blob>";
      deepEqual(answer, {
        "attachment": "ab",
        "data": "<blob>",
        "digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
          "ed343e6c739e54131fcb3a56e4bc1bd",
        "id": "a",
        "method": "getAttachment",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "Get first attachment");
      return jIO.util.readBlobAsText(blob).then(function (e) {
        deepEqual(blob.type, "text/plain", "Check blob type");
        deepEqual(e.target.result, "aba", "Check blob text content");
      }, function (err) {
        deepEqual(err, "no error", "Check blob text content");
      });
    }

    function getLastDocument() {
      return jio.get({"_id": "a"});
    }

    function getLastDocumentTest(answer) {
      deepEqual(answer, {
        "data": {
          "_id": "a",
          "title": "Hoo",
          "_attachments": {
            "aa": {
              "content_type": "text/plain",
              "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
                "0728e095ff24218119d51bd22475363",
              "length": 3
            },
            "ab": {
              "content_type": "text/plain",
              "digest": "sha256-e124adcce1fb2f88e1ea799c3d0820845" +
                "ed343e6c739e54131fcb3a56e4bc1bd",
              "length": 3
            }
          }
        },
        "id": "a",
        "method": "get",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "Get last document metadata");
    }

    function removeSecondAttachment() {
      return jio.removeAttachment({"_id": "a", "_attachment": "ab"});
    }

    function removeSecondAttachmentTest(answer) {
      deepEqual(answer, {
        "attachment": "ab",
        "id": "a",
        "method": "removeAttachment",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Remove second document");
    }

    function getInexistentSecondAttachment() {
      return success(jio.getAttachment({"_id": "a", "_attachment": "ab"}));
    }

    function getInexistentSecondAttachmentTest(answer) {
      deepEqual(answer, {
        "attachment": "ab",
        "error": "not_found",
        "id": "a",
        "message": "DavStorage, unable to get attachment.",
        "method": "getAttachment",
        "reason": "missing attachment",
        "result": "error",
        "status": 404,
        "statusText": "Not Found"
      }, "Get inexistent second attachment");
    }

    function getOneAttachmentDocument() {
      return jio.get({"_id": "a"});
    }

    function getOneAttachmentDocumentTest(answer) {
      deepEqual(answer, {
        "data": {
          "_attachments": {
            "aa": {
              "content_type": "text/plain",
              "digest": "sha256-38760eabb666e8e61ee628a17c4090cc5" +
                "0728e095ff24218119d51bd22475363",
              "length": 3
            }
          },
          "_id": "a",
          "title": "Hoo"
        },
        "id": "a",
        "method": "get",
        "result": "success",
        "status": 200,
        "statusText": "Ok"
      }, "Get document metadata");
    }

    function removeSecondAttachmentAgain() {
      return success(jio.removeAttachment({"_id": "a", "_attachment": "ab"}));
    }

    function removeSecondAttachmentAgainTest(answer) {
      deepEqual(answer, {
        "attachment": "ab",
        "error": "not_found",
        "id": "a",
        "message": "DavStorage, document attachment not found.",
        "method": "removeAttachment",
        "reason": "missing attachment",
        "result": "error",
        "status": 404,
        "statusText": "Not Found"
      }, "Remove inexistent attachment");
    }

    function removeDocument() {
      return jio.remove({"_id": "a"});
    }

    function removeDocumentTest(answer) {
      deepEqual(answer, {
        "id": "a",
        "method": "remove",
        "result": "success",
        "status": 204,
        "statusText": "No Content"
      }, "Remove document and its attachments");
    }

    function getInexistentFirstAttachment() {
      return success(jio.getAttachment({"_id": "a", "_attachment": "aa"}));
    }

    function getInexistentFirstAttachmentTest(answer) {
      deepEqual(answer, {
        "attachment": "aa",
        "error": "not_found",
        "id": "a",
        "message": "DavStorage, unable to get attachment.",
        "method": "getAttachment",
        "reason": "missing document",
        "result": "error",
        "status": 404,
        "statusText": "Not Found"
      }, "Get inexistent first attachment");
    }

    function getInexistentDocument() {
      return success(jio.get({"_id": "a"}));
    }

    function getInexistentDocumentTest(answer) {
      deepEqual(answer, {
        "error": "not_found",
        "id": "a",
        "message": "DavStorage, unable to get document.",
        "method": "get",
        "reason": "Not Found",
        "result": "error",
        "status": 404,
        "statusText": "Not Found"
      }, "Get inexistent document");
    }

    function removeInexistentDocument() {
      return success(jio.remove({"_id": "a"}));
    }

    function removeInexistentDocumentTest(answer) {
      deepEqual(answer, {
        "error": "not_found",
        "id": "a",
        "message": "DavStorage, unable to get metadata.",
        "method": "remove",
        "reason": "Not Found",
        "result": "error",
        "status": 404,
        "statusText": "Not Found"
      }, "Remove already removed document");
    }

    function unexpectedError(error) {
      if (error instanceof Error) {
        deepEqual([
          error.name + ": " + error.message,
          error
        ], "UNEXPECTED ERROR", "Unexpected error");
      } else {
        deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
      }
    }

    // # Post new documents, list them and remove them
    // post a 201
    postNewDocument().done(postNewDocumentTest).
      // get 200
      then(getCreatedDocument).done(getCreatedDocumentTest).
      // post b 201
      then(postSpecificDocument).done(postSpecificDocumentTest).
      // allD 200 2 documents
      then(listDocuments).done(list2DocumentsTest).
      // remove a 204
      then(removeCreatedDocument).done(removeCreatedDocumentTest).
      // remove b 204
      then(removeSpecificDocument).done(removeSpecificDocumentTest).
      // allD 200 empty storage
      then(listEmptyStorage).done(listEmptyStorageTest).
      // # Create and update documents, and some attachment and remove them
      // put 201
      then(putNewDocument).done(putNewDocumentTest).
      // get 200
      then(getCreatedDocument2).done(getCreatedDocument2Test).
      // post 409
      then(postSameDocument).done(postSameDocumentTest).
      // putA a 204
      then(createAttachment).done(createAttachmentTest).
      // putA a 204
      then(updateAttachment).done(updateAttachmentTest).
      // putA b 204
      then(createAnotherAttachment).done(createAnotherAttachmentTest).
      // put 204
      then(updateLastDocument).done(updateLastDocumentTest).
      // getA a 200
      then(getFirstAttachment).
      then(getFirstAttachmentTest).
      // getA b 200
      then(getSecondAttachment).
      then(getSecondAttachmentTest).
      // get 200
      then(getLastDocument).done(getLastDocumentTest).
      // removeA b 204
      then(removeSecondAttachment).done(removeSecondAttachmentTest).
      // getA b 404
      then(getInexistentSecondAttachment).
      done(getInexistentSecondAttachmentTest).
      // get 200
      then(getOneAttachmentDocument).done(getOneAttachmentDocumentTest).
      // removeA b 404
      then(removeSecondAttachmentAgain).done(removeSecondAttachmentAgainTest).
      // remove 204
      then(removeDocument).done(removeDocumentTest).
      // getA a 404
      then(getInexistentFirstAttachment).done(getInexistentFirstAttachmentTest).
      // get 404
      then(getInexistentDocument).done(getInexistentDocumentTest).
      // remove 404
      then(removeInexistentDocument).done(removeInexistentDocumentTest).
      // check 204
      //then(checkDocument).done(checkDocumentTest).
      //then(checkStorage).done(checkStorageTest).
      fail(unexpectedError).
      always(start).
      always(server.restore.bind(server));

  });

}());