Commit 038c7a51 authored by Bryan Kaperick's avatar Bryan Kaperick

Implemented absolute, consistent, and leaves style getting of old revisions of...

Implemented absolute, consistent, and leaves style getting of old revisions of documents and one large test case with three users to validate these methods.
parent edae97f3
......@@ -27,6 +27,7 @@
sub_storage: spec.sub_storage
});
this._lastseen = undefined;
this.param = true;
}
BryanStorage.prototype.get = function (id_in, revision) {
......@@ -47,6 +48,14 @@
revision.path = "absolute";
}
if (revision.steps === undefined) {
revision.steps = 0;
}
if (revision.steps === 0) {
revision.path = "absolute";
}
// Query to get the last edit made to this document
var storage = this,
substorage = this._sub_storage,
......@@ -55,6 +64,72 @@
sort_on: [["timestamp", "descending"]]
};
if (revision.path === "leaves") {
return substorage.allDocs({
query: "leaf: true",
sort_on: [["timestamp", "descending"]]
})
.push(function (results) {
var promises = results.data.rows.map(function (res) {
return substorage.get(res.id);
});
return RSVP.all(promises);
})
.push(function (documents) {
var not_leaves = {},
leaves = [],
ind,
doc_data,
fix_leaves = [];
function update_leaf_state(data) {
var new_data = data;
new_data.leaf = false;
return substorage.put(data.timestamp, new_data);
}
// Loop through documents and push only leaf versions to leaves array
for (ind = 0; ind < documents.length; ind += 1) {
doc_data = documents[ind];
not_leaves[doc_data.lastseen] = true;
if (not_leaves[doc_data.timestamp] === true) {
fix_leaves.push(update_leaf_state);
} else {
if (doc_data.op === "put") {
// XXX: For cheaper evaluation, break out of the loop once
// leaves.length == revision.steps, and only fix the leaves in
// fix_leaves at that point.
// However, since we already spent time to retrieve all leaves,
// it may be better to go ahead and clean up all mislabelled
// leaves right now, so the next call to get.leaves is cheaper
leaves.push(doc_data.doc);
// revision.steps is guaranteed to be >= 1 in this branch
//
if (leaves.length - 1 === revision.steps) {
storage._lastseen = doc_data.timestamp;
}
}
}
}
// Fix all mislabelled leaves and then return the array of leaves
return RSVP.all(fix_leaves)
//XXX: Not sure why I can't use a .push here instead of .then
.then(function () {
if (leaves.length - 1 >= revision.steps) {
return leaves[revision.steps];
}
throw new jIO.util.jIOError(
"bryanstorage: there are fewer than " +
revision.steps + " leaf revisions for '" + id_in + "'",
404
);
});
});
}
// In "absolute" path, .get returns the revision.steps-most-recent revision
if (revision.path === "absolute") {
options.limit = [revision.steps, 1];
......@@ -147,7 +222,8 @@
doc_id: id,
doc: data,
op: "put",
lastseen: this._lastseen
lastseen: this._lastseen,
leaf: true
};
this._lastseen = timestamp;
//console.log(metadata.doc.k, timestamp, metadata.lastseen);
......@@ -161,9 +237,11 @@
timestamp: timestamp,
doc_id: id,
op: "remove",
lastseen: this._lastseen
lastseen: this._lastseen,
leaf: true
};
this._lastseen = timestamp;
//console.log("removed", timestamp, metadata.lastseen);
return this._sub_storage.put(timestamp, metadata);
};
......
......@@ -84,7 +84,8 @@
},
timestamp: results.timestamp,
op: "put",
lastseen: undefined
lastseen: undefined,
leaf: true
}, "The first item in the log is pushing bar's title to 'foo0'");
return jio.remove("bar");
})
......@@ -119,7 +120,8 @@
doc_id: "bar",
timestamp: result.timestamp,
op: "remove",
lastseen: result.lastseen
lastseen: result.lastseen,
leaf: true
});
})
.fail(function (error) {
......@@ -391,7 +393,7 @@
test("Testing retrieval of older revisions of documents with multiple users",
function () {
stop();
expect(35);
expect(51);
// create storage of type "bryan" with memory as substorage
var dbname = "multi_user_db" + Date.now(),
......@@ -493,8 +495,10 @@
// Test all lastseens are the same
.push(function () {
equal(jio1._lastseen, jio2._lastseen, "All users see same revision");
equal(jio1._lastseen, jio3._lastseen, "All users see same revision");
// These are all undefined outside the storage definition, so these
// tests are meaningless
//equal(jio1._lastseen, jio2._lastseen, "All users see same version");
//equal(jio1._lastseen, jio3._lastseen, "All users see same version");
//
// Test consistent history of user 1
......@@ -682,6 +686,10 @@
404,
"There are only 3 previous states of this document");
})
// Reset jio3._lastseen to be at v0.1.3.3.3
.push(function () {
return jio3.get("doc");
})
//
// Test absolute history of user 1
......@@ -875,6 +883,241 @@
"There are only 3 previous states of this document");
})
//
// Tests on checking out an older revision and making a new edit branch
//
.push(function () {
return jio1.get("doc", {
path: "absolute",
steps: 1
});
})
.push(function () {
return jio1.put("doc", {
"k": "v0.1.2.2.2.1"
});
})
.push(function () {
return jio1.get("doc", {
path: "consistent",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2"
}, "The new document is added to the correct edit branch"
);
return jio1.get("doc", {
path: "consistent",
steps: 2
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"This document was removed at this time");
return jio1.get("doc", {
path: "consistent",
steps: 3
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2"
}, "The new document is added to the correct edit branch"
);
return jio1.get("doc", {
path: "consistent",
steps: 4
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1"
}, "This edit branch also leads back to the original version"
);
return jio1.get("doc", {
path: "consistent",
steps: 5
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are no revisions before the original document");
})
.push(function () {
return jio3.put("doc", {
"k": "v0.1.3.3.3.3"
});
})
// All three users have the same latest revision
.push(function () {
return jio1.get("doc");
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "User one accesses latest revision correctly"
);
return jio2.get("doc");
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "User two accesses latest revision correctly"
);
return jio3.get("doc");
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "User three accesses latest revision correctly"
);
return jio2.get("doc", {
path: "consistent",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3"
}, "User 2 accesses the 1st edit in consistent traversal."
);
})
//
// Testing .getting on leaf nodes
//
.push(function () {
return jio1.get("doc", {
path: "leaves"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "First result is the most-recently-added leaf"
);
return jio2.get("doc", {
path: "leaves",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2.1"
}, "Second result is the 2nd most-recently-added leaf"
);
return jio3.get("doc", {
path: "leaves",
steps: 2,
db: "jio3"
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.1"
}, "Third result is the 3rd most-recently-added leaf"
);
//
// Editing document revisions stemming from the latest leaf nodes seen
//
return jio1.put("doc", {
"k": "v0.1.3.3.3.3.1"
});
})
.push(function () {
return jio3.remove("doc"); // removing v0.1.3.3.1
})
// Check that jio1 sees latest non-removed revision
.push(function () {
return jio1.get("doc");
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"The most recent edit was a remove, so throw error");
})
.push(function () {
// jio2 lastseen should point to "v0.1.2.2.2.1"
return jio2.put("doc", {
"k": "v0.1.2.2.2.1.2"
});
})
.push(function () {
return jio1.get("doc", {
path: "leaves",
steps: 0
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.2.2.2.1.2"
}, "Accessing the first leaf node at this time"
);
return jio1.get("doc", {
path: "leaves",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3.1"
}, "Accessing the second leaf node at this time"
);
return jio1.get("doc", {
path: "leaves",
steps: 2
});
})
.push(function () {
ok(false, "This query should have thrown a 404 error");
},
function (error) {
deepEqual(error.status_code,
404,
"There are only two non-removed leaves");
// jio1 should still have lastseen at v0.1.3.3.3.3.1
return jio1.put("doc", {
"k": "v0.1.3.3.3.3.1.1"
});
})
.push(function () {
return jio1.get("doc", {
path: "consistent",
steps: 1
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3.1"
}, "If a .get fails, that should not reset ._lastseen parameter"
);
return jio1.get("doc", {
path: "consistent",
steps: 2
});
})
.push(function (result) {
deepEqual(result, {
"k": "v0.1.3.3.3.3"
}, "History of 0.1.2.2.2 has been constructed correctly.");
})
.fail(function (error) {
//console.log(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