Commit 9bf585e5 authored by Bryan Kaperick's avatar Bryan Kaperick

Added additional tests for edgecase behavior.

parent 923a85d2
...@@ -46,31 +46,27 @@ ...@@ -46,31 +46,27 @@
HistoryStorage.prototype.get = function (id_in) { HistoryStorage.prototype.get = function (id_in) {
// Query to get the last edit made to this document
var substorage = this._sub_storage,
doc_id_query,
metadata_query,
options;
if (this._include_revisions) { if (this._include_revisions) {
// Try to treat id_in as a timestamp instead of a name doc_id_query = new SimpleQuery({
return this._sub_storage.get(id_in) operator: "<=",
.push(function (result) { key: "timestamp",
if (result.op === "put") { value: id_in
return result.doc;
}
throwRemovedError(id_in);
}, function (error) {
if (error.status_code === 404 &&
error instanceof jIO.util.jIOError) {
throwCantFindError(id_in);
}
throw error;
}); });
} else {
doc_id_query = new SimpleQuery({key: "doc_id", value: id_in});
} }
// Query to get the last edit made to this document
var substorage = this._sub_storage,
// Include id_in as value in query object for safety // Include id_in as value in query object for safety
metadata_query = new ComplexQuery({ metadata_query = new ComplexQuery({
operator: "AND", operator: "AND",
query_list: [ query_list: [
new SimpleQuery({key: "doc_id", value: id_in}), doc_id_query,
new ComplexQuery({ new ComplexQuery({
operator: "OR", operator: "OR",
query_list: [ query_list: [
...@@ -79,13 +75,15 @@ ...@@ -79,13 +75,15 @@
] ]
}) })
] ]
}), });
options = { options = {
query: metadata_query, query: metadata_query,
select_list: ["op"], select_list: ["op"],
limit: [0, 1], limit: [0, 1],
sort_on: [["timestamp", "descending"]] sort_on: [["timestamp", "descending"]]
}; };
return substorage.allDocs(options) return substorage.allDocs(options)
.push(function (results) { .push(function (results) {
if (results.data.total_rows > 0) { if (results.data.total_rows > 0) {
...@@ -102,7 +100,6 @@ ...@@ -102,7 +100,6 @@
}; };
HistoryStorage.prototype.put = function (id, data) { HistoryStorage.prototype.put = function (id, data) {
var timestamp = generateUniqueTimestamp(Date.now()), var timestamp = generateUniqueTimestamp(Date.now()),
metadata = { metadata = {
// XXX: remove this attribute once query can sort_on id // XXX: remove this attribute once query can sort_on id
...@@ -133,9 +130,11 @@ ...@@ -133,9 +130,11 @@
query_removed_check, query_removed_check,
options, options,
query_doc_id, query_doc_id,
options_remcheck; options_remcheck,
include_revs = this._include_revisions,
have_seen_id = false;
if (this._include_revisions) { if (include_revs) {
query_doc_id = new SimpleQuery({ query_doc_id = new SimpleQuery({
operator: "<=", operator: "<=",
key: "timestamp", key: "timestamp",
...@@ -143,6 +142,7 @@ ...@@ -143,6 +142,7 @@
}); });
} else { } else {
query_doc_id = new SimpleQuery({key: "doc_id", value: id}); query_doc_id = new SimpleQuery({key: "doc_id", value: id});
have_seen_id = true;
} }
query_removed_check = new ComplexQuery({ query_removed_check = new ComplexQuery({
...@@ -177,7 +177,7 @@ ...@@ -177,7 +177,7 @@
options_remcheck = { options_remcheck = {
query: query_removed_check, query: query_removed_check,
select_list: ["op", "timestamp"], select_list: ["op", "timestamp"],
//limit: [0, 1], limit: [0, 1],
sort_on: [["timestamp", "descending"]] sort_on: [["timestamp", "descending"]]
}; };
options = { options = {
...@@ -187,8 +187,12 @@ ...@@ -187,8 +187,12 @@
}; };
return this._sub_storage.allDocs(options_remcheck) return this._sub_storage.allDocs(options_remcheck)
// Check the document exists and is not removed
.push(function (results) { .push(function (results) {
if (results.data.total_rows > 0) { if (results.data.total_rows > 0) {
if (results.data.rows[0].id === id) {
have_seen_id = true;
}
if (results.data.rows[0].value.op === "remove") { if (results.data.rows[0].value.op === "remove") {
throwRemovedError(id); throwRemovedError(id);
} }
...@@ -205,6 +209,18 @@ ...@@ -205,6 +209,18 @@
attachment_promises = [], attachment_promises = [],
ind, ind,
entry; entry;
// If input mapped to a real timestamp, then the first query result must
// have the inputted id. Otherwise, unexpected results could arise
// by inputting nonsensical strings as id when include_revisions = true
if (include_revs &&
results.data.total_rows > 0 &&
results.data.rows[0].id !== id &&
!have_seen_id) {
throwCantFindError(id);
}
// Only return attachments if: // Only return attachments if:
// (it is the most recent revision) AND (it is a putAttachment) // (it is the most recent revision) AND (it is a putAttachment)
attachments = results.data.rows.filter(function (docum) { attachments = results.data.rows.filter(function (docum) {
...@@ -257,7 +273,6 @@ ...@@ -257,7 +273,6 @@
// Query to get the last edit made to this document // Query to get the last edit made to this document
var substorage = this._sub_storage, var substorage = this._sub_storage,
// Include id_in as value in query object for safety
// "doc_id: id AND // "doc_id: id AND
// (op: remove OR ((op: putAttachment OR op: removeAttachment) AND // (op: remove OR ((op: putAttachment OR op: removeAttachment) AND
// name: name))" // name: name))"
...@@ -295,6 +310,7 @@ ...@@ -295,6 +310,7 @@
return substorage.allDocs(options) return substorage.allDocs(options)
.push(function (results) { .push(function (results) {
if (results.data.total_rows > 0) { if (results.data.total_rows > 0) {
// XXX: issue if attachments are put on a removed document
if (results.data.rows[0].value.op === "remove" || if (results.data.rows[0].value.op === "remove" ||
results.data.rows[0].value.op === "removeAttachment") { results.data.rows[0].value.op === "removeAttachment") {
throwRemovedError(id); throwRemovedError(id);
...@@ -324,8 +340,6 @@ ...@@ -324,8 +340,6 @@
}; };
HistoryStorage.prototype.buildQuery = function (options) { HistoryStorage.prototype.buildQuery = function (options) {
// XXX: if include_revisions, we should also include the document results
// for different edits of attachments
// Set default values // Set default values
if (options === undefined) {options = {}; } if (options === undefined) {options = {}; }
if (options.query === undefined) {options.query = ""; } if (options.query === undefined) {options.query = ""; }
...@@ -338,76 +352,68 @@ ...@@ -338,76 +352,68 @@
options.query = jIO.QueryFactory.create(options.query); options.query = jIO.QueryFactory.create(options.query);
var meta_options, var meta_options,
substorage = this._sub_storage, include_revs = this._include_revisions,
// Check if query involved _timestamp.
// If not, use default behavior and only query on latest revisions
rev_query = this._include_revisions,
doc_id_name, doc_id_name,
timestamp_name; timestamp_name;
// Query for all edits putting or removing documents (and nothing about // Query for all edits
// attachments)
meta_options = { meta_options = {
query: "",//(op: remove) OR (op: put)", query: "",
sort_on: options.sort_on sort_on: options.sort_on,
select_list: ["doc", "op", "doc_id"]
}; };
return this._sub_storage.allDocs(meta_options) return this._sub_storage.allDocs(meta_options)
// Get all documents found in query
// XXX: Once include_docs is implemented, this step can be simplified
.push(function (results) {
var promises = results.data.rows.map(function (data) {
return substorage.get(data.id);
});
return RSVP.all(promises);
})
.push(function (results) { .push(function (results) {
results = results.data.rows;
var seen = {}, var seen = {},
query_matches, query_matches,
docs_to_query, docs_to_query,
i; i;
doc_id_name = "_doc_id"; doc_id_name = "_doc_id";
timestamp_name = "_timestamp"; timestamp_name = "_timestamp";
for (i = 0; i < results.length; i += 1) { for (i = 0; i < results.length; i += 1) {
if (results[i].op === "put") { if (results[i].value.op === "put") {
while (results[i].doc.hasOwnProperty(doc_id_name)) { while (results[i].value.doc.hasOwnProperty(doc_id_name)) {
doc_id_name = "_" + doc_id_name; doc_id_name = "_" + doc_id_name;
} }
while (results[i].doc.hasOwnProperty(timestamp_name)) { while (results[i].value.doc.hasOwnProperty(timestamp_name)) {
timestamp_name = "_" + timestamp_name; timestamp_name = "_" + timestamp_name;
} }
} }
} }
if (rev_query) { if (include_revs) {
// We only query on versions mapping to puts or putAttachments // We only query on versions mapping to puts or putAttachments
results = results.map(function (docum, ind) { results = results.map(function (docum, ind) {
var data_key; var data_key;
if (docum.op === "put") { if (docum.value.op === "put") {
return docum; return docum;
} }
if (docum.op === "putAttachment") { if (docum.value.op === "remove") {
docum.value.doc = {};
return docum;
}
if (docum.value.op === "putAttachment" ||
docum.value.op === "removeAttachment") {
// putAttachment document does not contain doc metadata, so we // putAttachment document does not contain doc metadata, so we
// add it from the most recent non-removed put on same id // add it from the most recent non-removed put on same id
docum.doc = {}; docum.value.doc = {};
for (i = ind + 1; i < results.length; i += 1) { for (i = ind + 1; i < results.length; i += 1) {
if (results[i].doc_id === docum.doc_id) { if (results[i].value.doc_id === docum.value.doc_id) {
if (results[i].op === "put") { if (results[i].value.op === "put") {
for (data_key in results[i].doc) { for (data_key in results[i].value.doc) {
if (results[i].doc.hasOwnProperty(data_key)) { if (results[i].value.doc.hasOwnProperty(data_key)) {
docum.doc[data_key] = results[i].doc[data_key]; docum.value.doc[data_key] =
results[i].value.doc[data_key];
} }
} }
return docum; return docum;
} }
// If most recent edit on document was a remove before this if (results[i].value.op === "remove") {
// attachment, then don't include attachment in query return docum;
if (results[i].doc_id === "remove") {
return false;
} }
} }
} }
...@@ -420,35 +426,36 @@ ...@@ -420,35 +426,36 @@
// edits // edits
results = results.map(function (docum, ind) { results = results.map(function (docum, ind) {
var data_key; var data_key;
if (docum.op === "put") { if (docum.value.op === "put") {
// Mark as read and include in query // Mark as read and include in query
if (!seen.hasOwnProperty(docum.doc_id)) { if (!seen.hasOwnProperty(docum.value.doc_id)) {
seen[docum.doc_id] = {}; seen[docum.value.doc_id] = {};
return docum; return docum;
} }
} else if (docum.op === "remove" || } else if (docum.value.op === "remove" ||
docum.op === "removeAttachment") { docum.value.op === "removeAttachment") {
// Mark as read but do not include in query // Mark as read but do not include in query
seen[docum.doc_id] = {}; seen[docum.value.doc_id] = {};
} else if (docum.op === "putAttachment") { } else if (docum.value.op === "putAttachment") {
// If latest edit, mark as read, add document metadata from most // If latest edit, mark as read, add document metadata from most
// recent put, and add to query // recent put, and add to query
if (!seen.hasOwnProperty(docum.doc_id)) { if (!seen.hasOwnProperty(docum.value.doc_id)) {
seen[docum.doc_id] = {}; seen[docum.value.doc_id] = {};
docum.doc = {}; docum.value.doc = {};
for (i = ind + 1; i < results.length; i += 1) { for (i = ind + 1; i < results.length; i += 1) {
if (results[i].doc_id === docum.doc_id) { if (results[i].value.doc_id === docum.value.doc_id) {
if (results[i].op === "put") { if (results[i].value.op === "put") {
for (data_key in results[i].doc) { for (data_key in results[i].value.doc) {
if (results[i].doc.hasOwnProperty(data_key)) { if (results[i].value.doc.hasOwnProperty(data_key)) {
docum.doc[data_key] = results[i].doc[data_key]; docum.value.doc[data_key] =
results[i].value.doc[data_key];
} }
} }
return docum; return docum;
} }
if (results[i].doc_id === "remove") { if (results[i].value.doc_id === "remove") {
// If most recent edit on document was a remove before // If most recent edit on document was a remove before
// this attachment, then don't include attachment in query // this attachment, then don't include attachment in query
return false; return false;
...@@ -462,16 +469,18 @@ ...@@ -462,16 +469,18 @@
} }
docs_to_query = results docs_to_query = results
// Filter out all docs flagged as false in previous map call
.filter(function (docum) { .filter(function (docum) {
return docum; return docum;
}) })
.map(function (docum) { .map(function (docum) {
// Save timestamp and id information for retrieval at the end of // Save timestamp and id information for retrieval at the end of
// buildQuery // buildQuery
docum.doc[timestamp_name] = docum.timestamp; docum.value.doc[timestamp_name] = docum.id;
docum.doc[doc_id_name] = docum.doc_id; docum.value.doc[doc_id_name] = docum.value.doc_id;
return docum.doc; return docum.value.doc;
}); });
// Return timestamp and id information from query // Return timestamp and id information from query
options.select_list.push(doc_id_name); options.select_list.push(doc_id_name);
options.select_list.push(timestamp_name); options.select_list.push(timestamp_name);
......
...@@ -202,6 +202,41 @@ ...@@ -202,6 +202,41 @@
.always(function () {start(); }); .always(function () {start(); });
}); });
test("get attachment immediately after removing it",
function () {
stop();
expect(3);
var jio = this.jio,
blob1 = this.blob1;
jio.put("doc", {title: "foo0"})
.push(function () {
return jio.putAttachment("doc", "attacheddata", blob1);
})
.push(function () {
return jio.removeAttachment("doc", "attacheddata");
})
.push(function () {
return jio.getAttachment("doc", "attacheddata");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
ok(error instanceof jIO.util.jIOError, "throws a jio error");
deepEqual(error.status_code,
404,
"allAttachments of a removed document throws a 404 error");
deepEqual(error.message,
"HistoryStorage: cannot find object 'doc' (removed)",
"Error is handled by Historystorage.");
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
});
test("Ordering of put and remove attachments is correct", test("Ordering of put and remove attachments is correct",
function () { function () {
...@@ -386,7 +421,7 @@ ...@@ -386,7 +421,7 @@
test("Correctness of allAttachments method on older revisions", test("Correctness of allAttachments method on older revisions",
function () { function () {
stop(); stop();
expect(8); expect(11);
var jio = this.jio, var jio = this.jio,
history = this.history, history = this.history,
not_history = this.not_history, not_history = this.not_history,
...@@ -488,6 +523,21 @@ ...@@ -488,6 +523,21 @@
data: blob11 data: blob11
}); });
}) })
.push(function () {
return history.allAttachments("not-a-timestamp-or-doc_id");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
ok(error instanceof jIO.util.jIOError, "throws a jio error");
deepEqual(error.status_code,
404,
"allAttachments of a removed document throws a 404 error");
deepEqual(error.message,
"HistoryStorage: cannot find object 'not-a-timestamp-or-doc_id'",
"Error is handled by Historystorage.");
})
.fail(function (error) { .fail(function (error) {
//console.log(error); //console.log(error);
ok(false, error); ok(false, error);
...@@ -496,6 +546,7 @@ ...@@ -496,6 +546,7 @@
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Querying older revisions // Querying older revisions
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -544,6 +595,118 @@ ...@@ -544,6 +595,118 @@
} }
}); });
test("Removing documents before putting them",
function () {
stop();
expect(4);
var jio = this.jio,
not_history = this.not_history,
timestamps;
jio.remove("doc")
.push(function () {
return jio.put("doc2", {title: "foo"});
})
.push(function () {
return jio.get("doc");
})
.push(function () {
ok(false, "This statement should not be reached");
}, function (error) {
ok(error instanceof jIO.util.jIOError, "Correct type of error");
deepEqual(error.status_code,
404,
"Correct status code for getting a non-existent document"
);
deepEqual(error.message,
"HistoryStorage: cannot find object 'doc' (removed)",
"Error is handled by history storage before reaching console");
})
.push(function () {
return not_history.allDocs({
select_list: ["timestamp"],
sort_on: [["timestamp", "ascending"]]
});
})
.push(function (results) {
timestamps = results.data.rows.map(function (d) {
return d.value.timestamp;
});
})
.push(function () {
return jio.allDocs({select_list: ["title"]});
})
.push(function (results) {
deepEqual(results.data.rows, [
{
id: "doc2",
value: {title: "foo"},
doc: {},
timestamp: timestamps[1]
}], "DOcument that was removed before being put is not retrieved");
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
});
test("Removing documents and then putting them",
function () {
stop();
expect(2);
var jio = this.jio,
history = this.history,
timestamps;
jio.remove("doc")
.push(function () {
return jio.put("doc", {title: "foo"});
})
.push(function () {
return jio.get("doc");
})
.push(function (result) {
deepEqual(result, {
title: "foo"
}, "A put was the most recent edit on 'doc'");
})
.push(function () {
return history.allDocs({
select_list: ["timestamp"]
});
})
.push(function (results) {
timestamps = results.data.rows.map(function (d) {
return d.timestamp;
});
})
.push(function () {
return history.allDocs({select_list: ["title"]});
})
.push(function (results) {
deepEqual(results.data.rows, [
{
id: "doc",
value: {title: "foo"},
doc: {},
timestamp: timestamps[0]
},
{
id: "doc",
value: {},
doc: {},
timestamp: timestamps[1]
}], "DOcument that was removed before being put is not retrieved");
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
});
test("Handling bad input", test("Handling bad input",
function () { function () {
stop(); stop();
...@@ -614,7 +777,7 @@ ...@@ -614,7 +777,7 @@
test("Getting a document with timestamp when include_revisions is false", test("Getting a document with timestamp when include_revisions is false",
function () { function () {
stop(); stop();
expect(9); expect(6);
var jio = this.jio, var jio = this.jio,
history = this.history, history = this.history,
timestamp; timestamp;
...@@ -654,10 +817,13 @@ ...@@ -654,10 +817,13 @@
"HistoryStorage: cannot find object '" + timestamp + "'", "HistoryStorage: cannot find object '" + timestamp + "'",
"Error is handled by history storage before reaching console"); "Error is handled by history storage before reaching console");
}) })
/**
* XXX: I don't think this test is necessary
.push(function () { .push(function () {
return history.get("doc"); return history.get("doc");
}) })
.push(function () { .push(function (res) {
console.log(res);
ok(false, "This statement should not be reached"); ok(false, "This statement should not be reached");
}, function (error) { }, function (error) {
//console.log(error); //console.log(error);
...@@ -670,6 +836,8 @@ ...@@ -670,6 +836,8 @@
"HistoryStorage: cannot find object 'doc'", "HistoryStorage: cannot find object 'doc'",
"Error is handled by history storage before reaching console"); "Error is handled by history storage before reaching console");
}) })
**/
.fail(function (error) { .fail(function (error) {
//console.log(error); //console.log(error);
ok(false, error); ok(false, error);
...@@ -920,6 +1088,52 @@ ...@@ -920,6 +1088,52 @@
.always(function () {start(); }); .always(function () {start(); });
}); });
test("Getting after attachments have been put",
function () {
stop();
expect(4);
var jio = this.jio,
history = this.history,
blob = new Blob(['a']),
edit_log;
jio.put("doc", {"title": "foo0"})
.push(function () {
return jio.putAttachment("doc", "attachment", blob);
})
.push(function () {
return jio.removeAttachment("doc", "attachment", blob);
})
.push(function () {
return jio.get("doc");
})
.push(function (res) {
deepEqual(res, {title: "foo0"});
return history.allDocs({select_list: ["title"]});
})
.push(function (results) {
edit_log = results.data.rows;
return history.get(edit_log[0].timestamp);
})
.push(function (result) {
deepEqual(result, {title: "foo0"});
return history.get(edit_log[1].timestamp);
})
.push(function (result) {
deepEqual(result, {title: "foo0"});
return history.get(edit_log[2].timestamp);
})
.push(function (result) {
deepEqual(result, {title: "foo0"});
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
});
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Querying older revisions // Querying older revisions
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1656,10 +1870,10 @@ ...@@ -1656,10 +1870,10 @@
}) })
.push(function () { .push(function () {
return history.allDocs({ return history.allDocs({
query: "NOT (date: >= 2 AND date: <= 3)", query: "NOT (date: >= 2 AND date: <= 3) AND " +
"(date: = 1 OR date: = 4)",
select_list: ["date", "non-existent-key", "type", "title"], select_list: ["date", "non-existent-key", "type", "title"],
sort_on: [["date", "descending"] sort_on: [["date", "descending"]]
]
}); });
}) })
.push(function (results) { .push(function (results) {
...@@ -1724,16 +1938,194 @@ ...@@ -1724,16 +1938,194 @@
type: "foo" type: "foo"
}, },
timestamp: timestamps[1] timestamp: timestamps[1]
}
],
"Query gives correct results in correct order");
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
});
test(
"allDocs with include_revisions with an attachment on a removed document",
function () {
stop();
expect(1);
var jio = this.jio,
history = this.history,
not_history = this.not_history,
timestamps,
blob = new Blob(['a']);
jio.put("document", {title: "foo"})
.push(function () {
return jio.remove("document");
})
.push(function () {
return jio.putAttachment("document", "attachment", blob);
})
// Get timestamps
.push(function () {
return not_history.allDocs({
sort_on: [["timestamp", "ascending"]]
});
})
.push(function (results) {
timestamps = results.data.rows.map(function (d) {
return d.id;
});
})
.push(function () {
return history.allDocs({select_list: ["title"]});
})
.push(function (results) {
deepEqual(results.data.rows, [
{
id: "document",
doc: {},
value: {},
timestamp: timestamps[2]
}, },
{ {
id: "document",
doc: {}, doc: {},
id: "doc",
value: {}, value: {},
timestamp: timestamps[1]
},
{
id: "document",
doc: {},
value: {title: "foo"},
timestamp: timestamps[0] timestamp: timestamps[0]
}],
"Attachment on removed document is handled correctly"
);
return not_history.allDocs({select_list: ["doc"]});
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
} }
], );
"Query gives correct results in correct order");
test("allDocs with include_revisions with a removed attachment",
function () {
stop();
expect(2);
var jio = this.jio,
history = this.history,
not_history = this.not_history,
timestamps,
blob = new Blob(['a']);
jio.put("document", {title: "foo"})
.push(function () {
return jio.putAttachment("document", "attachment", blob);
})
.push(function () {
return jio.removeAttachment("document", "attachment");
})
// Get timestamps
.push(function () {
return not_history.allDocs({
sort_on: [["timestamp", "ascending"]]
});
})
.push(function (results) {
timestamps = results.data.rows.map(function (d) {
return d.id;
});
})
.push(function () {
return history.allDocs({select_list: ["title"]});
})
.push(function (results) {
deepEqual(results.data.rows, [
{
id: "document",
doc: {},
value: {title: "foo"},
timestamp: timestamps[2]
},
{
id: "document",
doc: {},
value: {title: "foo"},
timestamp: timestamps[1]
},
{
id: "document",
doc: {},
value: {title: "foo"},
timestamp: timestamps[0]
}],
"Attachment on removed document is handled correctly"
);
})
.push(function () {
return jio.allAttachments("document");
}) })
.push(function (results) {
deepEqual(results, {}, "No non-removed attachments");
})
.fail(function (error) {
//console.log(error);
ok(false, error);
})
.always(function () {start(); });
});
test("Parallel edits will not break anything",
function () {
stop();
expect(2);
var jio = this.jio,
history = this.history,
blob1 = new Blob(['ab']),
blob2 = new Blob(['abc']),
blob3 = new Blob(['abcd']);
jio.put("doc", {k: "v0"})
.push(function () {
return RSVP.all([
jio.put("doc", {k: "v"}),
jio.putAttachment("doc", "data", blob1),
jio.putAttachment("doc", "data2", blob2),
jio.putAttachment("doc", "data", blob3),
jio.removeAttachment("doc", "data"),
jio.removeAttachment("doc", "data2"),
jio.remove("doc"),
jio.remove("doc"),
jio.put("doc", {k: "v"}),
jio.put("doc", {k: "v"}),
jio.put("doc2", {k: "foo"}),
jio.remove("doc"),
jio.remove("doc")
]);
})
.push(function () {
ok(true, "No errors thrown.");
return history.allDocs();
})
.push(function (results) {
var res = results.data.rows;
equal(res.length,
14,
"All edits are recorded regardless of ordering");
return jio.allDocs();
})
.fail(function (error) { .fail(function (error) {
//console.log(error); //console.log(error);
ok(false, error); ok(false, error);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment