Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] JS tests on 2.0 — DO NOT MERGE YET #354

Closed
wants to merge 14 commits into from
Closed
11 changes: 8 additions & 3 deletions Makefile
Expand Up @@ -160,9 +160,14 @@ eunit: couch
@${REBAR} -r eunit skip_deps=meck,mochiweb,lager,snappy,folsom

javascript: all
# TODO: Fix tests to look for these files in their new path
@mkdir -p share/www/script/test
@cp test/javascript/tests/lorem*.txt share/www/script/test/
@mkdir -p share/www/test
ifeq ($(IN_RELEASE), true)
@cp test/javascript/tests/lorem*.txt share/www/test/
else
@mkdir -p src/fauxton/dist/release/test
@cp test/javascript/tests/lorem*.txt src/fauxton/dist/release/test/
endif
# 2 remedy problems w/ "internal server error" remove dev/lib
@dev/run -q --with-admin-party-please test/javascript/run
@rm -rf share/www/script

Expand Down
2 changes: 1 addition & 1 deletion configure
Expand Up @@ -668,5 +668,5 @@ fi
# only update dependencies, when we are not in a release tarball
if [ -d .git -a $SKIP_DEPS -ne 1 ]; then
echo "==> updating dependencies"
${REBAR} get-deps update-deps
${REBAR} get-deps # update-deps
fi
36 changes: 32 additions & 4 deletions test/javascript/couch.js
Expand Up @@ -13,7 +13,8 @@
// A simple class to represent a database. Uses XMLHttpRequest to interface with
// the CouchDB server.

function CouchDB(name, httpHeaders) {
function CouchDB(name, httpHeaders, globalRequestOptions) {
this.globalRequestOptions = globalRequestOptions || {}
this.name = name;
this.uri = "/" + encodeURIComponent(name) + "/";

Expand All @@ -24,6 +25,7 @@ function CouchDB(name, httpHeaders) {
this.request = function(method, uri, requestOptions) {
requestOptions = requestOptions || {};
requestOptions.headers = combine(requestOptions.headers, httpHeaders);
requestOptions.url = globalRequestOptions;
return CouchDB.request(method, uri, requestOptions);
};

Expand Down Expand Up @@ -156,12 +158,20 @@ function CouchDB(name, httpHeaders) {
body.options = options.options;
delete options.options;
}
this.last_req = this.request("POST", this.uri + "_temp_view"
+ encodeOptions(options), {
var ddoc = {
views: {
view: body
}
};
var ddoc_name = "_design/temp_" + get_random_string();
this.last_req = this.request("PUT", this.uri + ddoc_name, {
headers: {"Content-Type": "application/json"},
body: JSON.stringify(body)
body: JSON.stringify(ddoc)
});
CouchDB.maybeThrowError(this.last_req);
this.last_req = this.request("GET", this.uri + ddoc_name + "/_view/view"
+ encodeOptions(options));
CouchDB.maybeThrowError(this.last_req);
return JSON.parse(this.last_req.responseText);
};

Expand Down Expand Up @@ -357,6 +367,8 @@ CouchDB.getVersion = function() {
};

CouchDB.reloadConfig = function() {
// diabled until cluser port gets /_config
return {};
CouchDB.last_req = CouchDB.request("POST", "/_config/_reload");
CouchDB.maybeThrowError(CouchDB.last_req);
return JSON.parse(CouchDB.last_req.responseText);
Expand Down Expand Up @@ -420,6 +432,22 @@ CouchDB.request = function(method, uri, options) {
options.headers["Accept"] = options.headers["Accept"] || options.headers["accept"] || "application/json";
var req = CouchDB.newXhr();
uri = CouchDB.proxyUrl(uri);

if (options.url) {
var params = '';
for (var key in options.url) {
var value = options.url[key]
params += key + '=' + value + '&'
}
// if uri already has a ? append with &
if (uri.indexOf('?') === -1) {
uri += '?' + params;
} else {
uri += '&' + params;
}
}
// console.log(uri);
// console.log(JSON.stringify(options, null, 2));
req.open(method, uri, false);
if (options.headers) {
var headers = options.headers;
Expand Down
12 changes: 12 additions & 0 deletions test/javascript/couch_test_runner.js
Expand Up @@ -363,6 +363,7 @@ function makeDocs(start, end, templateDoc) {
}

function run_on_modified_server(settings, fun) {
throw new Error("_config not available on cluster")
try {
// set the settings
for(var i=0; i < settings.length; i++) {
Expand Down Expand Up @@ -463,3 +464,14 @@ CouchDB.prepareUserDoc = function(user_doc, new_password) {
}
return user_doc;
};

function get_random_string() {
return Math.random()
.toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 8);
}

function get_random_db_name() {
return "test_suite_db_" + get_random_string()
}
1 change: 1 addition & 0 deletions test/javascript/couchdb.uri
@@ -0,0 +1 @@
http://127.0.0.1:15984/
2 changes: 1 addition & 1 deletion test/javascript/run
Expand Up @@ -71,7 +71,7 @@ def mkformatter(tests):

def run_couchjs(test, fmt):
fmt(test)
cmd = [COUCHJS, "-H"] + SCRIPTS + [test, RUNNER]
cmd = [COUCHJS, "-H"] + ["-u", "test/javascript/couchdb.uri"] + SCRIPTS + [test, RUNNER]
p = sp.Popen(
cmd,
stdin=sp.PIPE,
Expand Down
95 changes: 57 additions & 38 deletions test/javascript/tests/all_docs.js
Expand Up @@ -11,17 +11,29 @@
// the License.

couchTests.all_docs = function(debug) {
var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
db.deleteDb();
var db_name = get_random_db_name();
var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"}, {w: 3});
db.createDb();
if (debug) debugger;

// Create some more documents.
// Notice the use of the ok member on the return result.
T(db.save({_id:"0",a:1,b:1}).ok);
T(db.save({_id:"3",a:4,b:16}).ok);
T(db.save({_id:"1",a:2,b:4}).ok);
T(db.save({_id:"2",a:3,b:9}).ok);

var doc1 = db.save({_id:"0",a:1,b:1});
var doc2 = db.save({_id:"3",a:4,b:16});
var doc3 = db.save({_id:"1",a:2,b:4});
var doc4 = db.save({_id:"2",a:3,b:9});

T(doc1.ok);
T(doc2.ok);
T(doc3.ok);
T(doc4.ok);

var revs = [];
revs.push(doc1.rev);
revs.push(doc2.rev);
revs.push(doc3.rev);
revs.push(doc4.rev);

// Check the all docs
var results = db.allDocs();
Expand All @@ -47,50 +59,52 @@ couchTests.all_docs = function(debug) {
});
TEquals(0, raw.rows.length);

// check that the docs show up in the seq view in the order they were created
var changes = db.changes();
var ids = ["0","3","1","2"];
for (var i=0; i < changes.results.length; i++) {
var row = changes.results[i];
T(row.id == ids[i], "seq order");
};

// it should work in reverse as well
changes = db.changes({descending:true});
ids = ["2","1","3","0"];
for (var i=0; i < changes.results.length; i++) {
var row = changes.results[i];
T(row.id == ids[i], "descending=true");
};
// check that all docs show up in the changes feed
// the order can vary
var changes = db.changes();
changes.results.forEach(function(row, idx) {
var rev = row.changes[0].rev;
TEquals(true, revs.indexOf(rev) !== -1, "doc " + i + " should be in changes");
});

// check that deletions also show up right
var doc1 = db.open("1");
var deleted = db.deleteDoc(doc1);
T(deleted.ok);
changes = db.changes();
// the deletion should make doc id 1 have the last seq num
T(changes.results.length == 4);
T(changes.results[3].id == "1");
T(changes.results[3].deleted);
var deleted_doc = changes.results.filter(function(row) {
return row.deleted == true;
})[0];
TEquals("1", deleted_doc.id, "deletes");

// do an update
var doc2 = db.open("3");
doc2.updated = "totally";
db.save(doc2);
var doc3 = db.open("3");
doc3.updated = "totally";
doc3 = db.save(doc3);
changes = db.changes();

// the update should make doc id 3 have the last seq num
T(changes.results.length == 4);
T(changes.results[3].id == "3");
var updated_doc = changes.results.filter(function(row) {
return row.id == doc3.id
})[0];
TEquals("3", updated_doc.id, "doc id should be 3");

// ok now lets see what happens with include docs
changes = db.changes({include_docs: true});
T(changes.results.length == 4);
T(changes.results[3].id == "3");
T(changes.results[3].doc.updated == "totally");

T(changes.results[2].doc);
T(changes.results[2].doc._deleted);
var updated_doc = changes.results.filter(function(row) {
return row.id == doc3.id
})[0];
T(updated_doc.doc.updated == "totally");

var deleted_doc = changes.results.filter(function(row) {
return row.deleted == true;
})[0];
TEquals(true, deleted_doc.doc._deleted, "deletes");

rows = db.allDocs({include_docs: true}, ["1"]).rows;
TEquals(1, rows.length);
Expand All @@ -112,13 +126,18 @@ couchTests.all_docs = function(debug) {
var winRev = db.open("3");

changes = db.changes({include_docs: true, conflicts: true, style: "all_docs"});
TEquals("3", changes.results[3].id);
TEquals(3, changes.results[3].changes.length);
TEquals(winRev._rev, changes.results[3].changes[0].rev);
TEquals("3", changes.results[3].doc._id);
TEquals(winRev._rev, changes.results[3].doc._rev);
TEquals(true, changes.results[3].doc._conflicts instanceof Array);
TEquals(2, changes.results[3].doc._conflicts.length);

var doc3 = changes.results.filter(function(row) {
return row.id == "3";
})[0];

TEquals("3", doc3.id);
TEquals(3, doc3.changes.length);
TEquals(winRev._rev, doc3.changes[0].rev);
TEquals("3", doc3.doc._id);
TEquals(winRev._rev, doc3.doc._rev);
TEquals(true, doc3.doc._conflicts instanceof Array);
TEquals(2, doc3.doc._conflicts.length);

rows = db.allDocs({include_docs: true, conflicts: true}).rows;
TEquals(3, rows.length);
Expand Down
17 changes: 9 additions & 8 deletions test/javascript/tests/attachment_names.js
Expand Up @@ -11,8 +11,8 @@
// the License.

couchTests.attachment_names = function(debug) {
var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
db.deleteDb();
var db_name = get_random_db_name();
var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"}, {w: 3});
db.createDb();
if (debug) debugger;

Expand All @@ -29,15 +29,15 @@ couchTests.attachment_names = function(debug) {
var save_response = db.save(goodDoc);
T(save_response.ok);

var xhr = CouchDB.request("GET", "/test_suite_db/good_doc/Колян.txt");
var xhr = CouchDB.request("GET", "/" + db_name + "/good_doc/Колян.txt");
T(xhr.responseText == "This is a base64 encoded text");
T(xhr.getResponseHeader("Content-Type") == "application/octet-stream");
TEquals("\"aEI7pOYCRBLTRQvvqYrrJQ==\"", xhr.getResponseHeader("Etag"));

var binAttDoc = {
_id: "bin_doc",
_attachments:{
"foo\x80txt": {
"footxt": {
content_type:"text/plain",
data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
}
Expand All @@ -53,7 +53,7 @@ couchTests.attachment_names = function(debug) {
var bin_data = "JHAPDO*AU£PN ){(3u[d 93DQ9¡€])} ææøo'∂ƒæ≤çæππ•¥∫¶®#†π¶®¥π€ª®˙π8np";


var xhr = (CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment\x80txt", {
var xhr = (CouchDB.request("PUT", "/" + db_name + "/bin_doc3/attachmenttxt", {
headers:{"Content-Type":"text/plain;charset=utf-8"},
body:bin_data
}));
Expand All @@ -64,8 +64,7 @@ couchTests.attachment_names = function(debug) {

// bulk docs
var docs = { docs: [binAttDoc] };

var xhr = CouchDB.request("POST", "/test_suite_db/_bulk_docs", {
var xhr = CouchDB.request("POST", "/" + db_name + "/_bulk_docs", {
body: JSON.stringify(docs)
});

Expand All @@ -88,9 +87,11 @@ couchTests.attachment_names = function(debug) {
TEquals(1, 2, "Attachment name with leading underscore saved. Should never show!");
} catch (e) {
TEquals("bad_request", e.error, "attachment_name: leading underscore");
TEquals("Attachment name can't start with '_'", e.reason, "attachment_name: leading underscore");
TEquals("Attachment name '_foo.txt' starts with prohibited character '_'", e.reason, "attachment_name: leading underscore");
}

// todo: form uploads, waiting for cmlenz' test case for form uploads
// cleanup
db.deleteDb();

};